Добавлен модуль для работы с (0x2B / 0x0E) Read Device Identification
This commit is contained in:
parent
e402334153
commit
3f1cd53e19
@ -32,6 +32,9 @@ SOURCES += \
|
||||
main.cpp \
|
||||
m3kte.cpp \
|
||||
multiplesettings.cpp \
|
||||
parameterbox.cpp \
|
||||
parameterdevice.cpp \
|
||||
parameterworkspace.cpp \
|
||||
scanboard.cpp \
|
||||
settingsdialog.cpp \
|
||||
writeregistermodel.cpp
|
||||
@ -43,6 +46,9 @@ HEADERS += \
|
||||
lineringer.h \
|
||||
m3kte.h \
|
||||
multiplesettings.h \
|
||||
parameterbox.h \
|
||||
parameterdevice.h \
|
||||
parameterworkspace.h \
|
||||
scanboard.h \
|
||||
settingsdialog.h \
|
||||
writeregistermodel.h
|
||||
@ -54,6 +60,9 @@ FORMS += \
|
||||
lineringer.ui \
|
||||
m3kte.ui \
|
||||
multiplesettings.ui \
|
||||
parameterbox.ui \
|
||||
parameterdevice.ui \
|
||||
parameterworkspace.ui \
|
||||
scanboard.ui \
|
||||
settingsdialog.ui
|
||||
|
||||
|
||||
@ -371,6 +371,8 @@ M3KTE::M3KTE(QWidget *parent)
|
||||
m_debugTerminalDialog->setMainTerm(this);
|
||||
m_regMultipleSettings = new MultipleSettings(this);
|
||||
modbusDevice = new QModbusRtuSerialMaster(this);
|
||||
m_parameterWorkspace = new ParameterWorkspace();
|
||||
m_parameterWorkspace->setModbusClient(modbusDevice);
|
||||
m_debugTerminalDialog->setModbusDevice(modbusDevice);
|
||||
connect(this, &M3KTE::boardReading, m_debugTerminalDialog, &DebugTerminalDialog::boardDebugReading);
|
||||
m_lineRinger = new LineRinger();
|
||||
@ -382,18 +384,10 @@ M3KTE::M3KTE(QWidget *parent)
|
||||
Boards[1].boardScanners->setSingleShot(true);
|
||||
Boards[2].boardScanners->setSingleShot(true);
|
||||
Boards[3].boardScanners->setSingleShot(true);
|
||||
connect(Boards[0].boardScanners, &QTimer::timeout, this, [this]() {
|
||||
boardScan(0);
|
||||
});
|
||||
connect(Boards[1].boardScanners, &QTimer::timeout, this, [this]() {
|
||||
boardScan(1);
|
||||
});
|
||||
connect(Boards[2].boardScanners, &QTimer::timeout, this, [this]() {
|
||||
boardScan(2);
|
||||
});
|
||||
connect(Boards[3].boardScanners, &QTimer::timeout, this, [this]() {
|
||||
boardScan(3);
|
||||
});
|
||||
connect(Boards[0].boardScanners, &QTimer::timeout, this, [this]() {boardScan(0);});
|
||||
connect(Boards[1].boardScanners, &QTimer::timeout, this, [this]() {boardScan(1);});
|
||||
connect(Boards[2].boardScanners, &QTimer::timeout, this, [this]() {boardScan(2);});
|
||||
connect(Boards[3].boardScanners, &QTimer::timeout, this, [this]() {boardScan(3);});
|
||||
{
|
||||
Boards[0].adr = 1;
|
||||
Boards[1].adr = 2;
|
||||
@ -459,13 +453,10 @@ M3KTE::M3KTE(QWidget *parent)
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
connect(Boards[i].localState[LOCAL_STATE_POLL], &QCheckBox::clicked,
|
||||
this, [i, this](bool checked) {
|
||||
m_deviceSettingsDialog->sendPollCommand(i, checked);
|
||||
});
|
||||
this, [i, this](bool checked) {m_deviceSettingsDialog->sendPollCommand(i, checked);});
|
||||
Boards[i].localState[LOCAL_STATE_WARN]->setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
||||
Boards[i].localState[LOCAL_STATE_ERR]->setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
||||
}
|
||||
|
||||
ui->BSM_Warning->setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
||||
ui->BSM_Accident->setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
||||
ui->BSM_WorkInProgress->setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
||||
@ -558,6 +549,7 @@ void M3KTE::initActions()
|
||||
connect(m_regMultipleSettings, &MultipleSettings::writeAndSend, this, &M3KTE::slotmultipleRegWriteAndSend);
|
||||
connect(ui->ConnectionMenuSettings, &QAction::triggered, m_settingsDialog, &QDialog::show);
|
||||
connect(ui->M3kteMenuSettings, &QAction::triggered, m_deviceSettingsDialog, &QDialog::show);
|
||||
connect(ui->ParameterScan, &QAction::triggered, m_parameterWorkspace, &QWidget::show);
|
||||
}
|
||||
|
||||
void M3KTE::logError(const QString &errorPlace, const QString &errorString, unsigned errorCount, const QString &description)
|
||||
@ -612,7 +604,9 @@ void M3KTE::onConnectClicked()
|
||||
} else {
|
||||
ui->ConnectionMenuConnect->setEnabled(false);
|
||||
ui->ConnectionMenuDisconnect->setEnabled(true);
|
||||
if(pingNetworkDevices()) { //Опрос устройств
|
||||
if(pingNetworkDevices()) //Опрос устройст
|
||||
{
|
||||
//m_parameterWorkspace->setDeviceCount(1);
|
||||
unsigned tmp_adr[4];
|
||||
bool ActiveDevices[4];
|
||||
for(int i = 0; i < 4; i++) {
|
||||
@ -635,6 +629,7 @@ void M3KTE::onConnectClicked()
|
||||
ui->BSM_Accident->setEnabled(true);
|
||||
ui->BSM_WorkInProgress->setEnabled(true);
|
||||
ui->BSM_WorkInProgress->setChecked(true);
|
||||
ui->ParameterScan->setEnabled(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -677,6 +672,7 @@ void M3KTE::onConnectClicked()
|
||||
ui->BSM_Accident->setEnabled(false);
|
||||
ui->BSM_WorkInProgress->setEnabled(false);
|
||||
ui->M3kteRegSettings->setEnabled(false);
|
||||
ui->ParameterScan->setEnabled(false);
|
||||
m_deviceSettingsDialog->onDisconnect();
|
||||
m_debugTerminalDialog->offAllBoard();
|
||||
}
|
||||
@ -777,8 +773,7 @@ void M3KTE::onWriteButtonClicked()
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply, tmp_id]() {
|
||||
if(reply->error() == QModbusDevice::ProtocolError) {
|
||||
statusBar()->showMessage(tr("Write response error: %1 (Mobus exception: 0x%2)")
|
||||
.arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16),
|
||||
5000);
|
||||
.arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16), 5000);
|
||||
logError(tr("Плата %1 (ID %2)").arg(tmp_id+1).arg(Boards[tmp_id].adr),
|
||||
reply->errorString(), ++Boards[tmp_id].error_TX,
|
||||
QString::number(reply->rawResult().exceptionCode(), 16));
|
||||
@ -1056,7 +1051,8 @@ void M3KTE::onSpeedUpdate()
|
||||
QPointer<M3KTE> safeThis(this);
|
||||
|
||||
connect(this, &M3KTE::errorAtCheckBoards, this, [safeThis]() {
|
||||
if (!safeThis) return;
|
||||
if (!safeThis)
|
||||
return;
|
||||
safeThis->disconnect(safeThis, &M3KTE::errorAtCheckBoards, safeThis, nullptr);
|
||||
safeThis->modbusDevice->setTimeout(safeThis->m_settingsDialog->settings().responseTime);
|
||||
safeThis->revertToOldSpeedAndRestart();
|
||||
@ -1064,7 +1060,8 @@ void M3KTE::onSpeedUpdate()
|
||||
});
|
||||
|
||||
connect(this, &M3KTE::successAtCheckBoards, this, [safeThis]() {
|
||||
if (!safeThis) return;
|
||||
if (!safeThis)
|
||||
return;
|
||||
safeThis->disconnect(safeThis, &M3KTE::successAtCheckBoards, safeThis, nullptr);
|
||||
safeThis->m_settingsDialog->UpdateBaud(safeThis->m_deviceSettingsDialog->currentSpeed());
|
||||
safeThis->modbusDevice->setTimeout(safeThis->m_settingsDialog->settings().responseTime);
|
||||
@ -1125,24 +1122,16 @@ void M3KTE::onParityUpdate()
|
||||
modbusDevice->setTimeout(500);
|
||||
QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, 174, 1);
|
||||
switch(m_deviceSettingsDialog->currentParity()) {
|
||||
case 0: //Нет контроля
|
||||
unit.setValue(0, 0x000);
|
||||
break;
|
||||
case 1: //Четный
|
||||
unit.setValue(0, 0x0400);
|
||||
break;
|
||||
case 2: //Нечетный
|
||||
unit.setValue(0, 0x0600);
|
||||
break;
|
||||
case 0: unit.setValue(0, 0x000); break; //Нет контроля
|
||||
case 1: unit.setValue(0, 0x0400); break;//Четный
|
||||
case 2: unit.setValue(0, 0x0600); break;//Нечетный
|
||||
}
|
||||
|
||||
// Используем shared pointers вместо ссылок на стековые переменные
|
||||
auto totalActiveBoards = QSharedPointer<int>::create(0);
|
||||
auto confirmedBoards = QSharedPointer<int>::create(0);
|
||||
auto pendingBoards = QSharedPointer<QSet<int>>::create();
|
||||
auto oldParity = m_settingsDialog->curParity(); // сохраняем старую четность для отката
|
||||
auto newParity = m_deviceSettingsDialog->currentParity();
|
||||
|
||||
// Лямбда для обработки результата
|
||||
auto processResult = [this, totalActiveBoards, confirmedBoards, oldParity, newParity]() {
|
||||
if(*confirmedBoards != *totalActiveBoards) {
|
||||
@ -1152,7 +1141,6 @@ void M3KTE::onParityUpdate()
|
||||
modbusDevice->disconnectDevice();
|
||||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, newParity);
|
||||
modbusDevice->connectDevice();
|
||||
|
||||
auto errorHandler = [this, oldParity]() {
|
||||
disconnect(this, &M3KTE::errorAtCheckBoards, this, nullptr);
|
||||
modbusDevice->setTimeout(m_settingsDialog->settings().responseTime);
|
||||
@ -1161,21 +1149,17 @@ void M3KTE::onParityUpdate()
|
||||
modbusDevice->connectDevice();
|
||||
beginScanBoards();
|
||||
};
|
||||
|
||||
auto successHandler = [this, newParity]() {
|
||||
disconnect(this, &M3KTE::successAtCheckBoards, this, nullptr);
|
||||
m_settingsDialog->UpdateParity(newParity);
|
||||
modbusDevice->setTimeout(m_settingsDialog->settings().responseTime);
|
||||
beginScanBoards();
|
||||
};
|
||||
|
||||
connect(this, &M3KTE::errorAtCheckBoards, this, errorHandler);
|
||||
connect(this, &M3KTE::successAtCheckBoards, this, successHandler);
|
||||
|
||||
checkBoards();
|
||||
}
|
||||
};
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
if(!Boards[i].isActive)
|
||||
continue;
|
||||
@ -1184,7 +1168,6 @@ void M3KTE::onParityUpdate()
|
||||
if(reply) {
|
||||
(*totalActiveBoards)++;
|
||||
pendingBoards->insert(slaveAdress);
|
||||
|
||||
connect(reply, &QModbusReply::finished, this,
|
||||
[this, i, reply, slaveAdress, totalActiveBoards, confirmedBoards, pendingBoards, processResult]() {
|
||||
if(reply->error() == QModbusDevice::TimeoutError) {
|
||||
@ -1405,6 +1388,14 @@ bool M3KTE::pingNetworkDevices()
|
||||
delete _unit_settings[2];
|
||||
}
|
||||
}
|
||||
int totalBoardsActive = 0;
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
if(Boards[i].isActive)
|
||||
totalBoardsActive++;
|
||||
}
|
||||
m_parameterWorkspace->setDeviceCount(totalBoardsActive);
|
||||
|
||||
modbusDevice->setNumberOfRetries(m_settingsDialog->settings().numberOfRetries);
|
||||
beginScanBoards();
|
||||
bar->deleteLater();
|
||||
@ -1413,11 +1404,13 @@ bool M3KTE::pingNetworkDevices()
|
||||
|
||||
void M3KTE::beginScanBoards()
|
||||
{
|
||||
int totalBoardsActive = 0;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
if(Boards[i].isActive) {
|
||||
m_debugTerminalDialog->setScanBoardActive(true, i);
|
||||
m_deviceSettingsDialog->initPollForBoard(i, Boards[i].adr);
|
||||
boardScan(i);
|
||||
m_parameterWorkspace->updateDevice(totalBoardsActive++, Boards[i].isActive, Boards[i].adr);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -1544,45 +1537,19 @@ void M3KTE::displayResultOfScan(QModbusReply *reply, int boardID, int status)
|
||||
}
|
||||
if (state) {
|
||||
switch (numb_err) {
|
||||
case 1:
|
||||
statusText += QString(" (Err 5 VD)");
|
||||
break;
|
||||
case 2:
|
||||
statusText += QString(" (Err 5 VA)");
|
||||
break;
|
||||
case 3:
|
||||
statusText += QString(" (Err 5 Vsci)");
|
||||
break;
|
||||
case 4:
|
||||
statusText += QString(" (Err 24 V)");
|
||||
break;
|
||||
case 5:
|
||||
statusText += QString(" (Hardfault)");
|
||||
break;
|
||||
case 6:
|
||||
statusText += QString(" (Empty Settings)");
|
||||
break;
|
||||
case 7:
|
||||
statusText += QString(" (ADC Error)");
|
||||
break;
|
||||
case 8:
|
||||
statusText += QString(" (Program Err 4)");
|
||||
break;
|
||||
case 9:
|
||||
statusText += QString(" (Program Err 5)");
|
||||
break;
|
||||
case 10:
|
||||
statusText += QString(" (EEPROM Error)");
|
||||
break;
|
||||
case 11:
|
||||
statusText += QString(" (Unstable discharge)");
|
||||
break;
|
||||
case 12:
|
||||
statusText += QString(" (RS/UART Errors)");
|
||||
break;
|
||||
default:
|
||||
statusText += QString(" (Program Err %1)").arg(numb_err - 4);
|
||||
break;
|
||||
case 1: statusText += QString(" (Err 5 VD)"); break;
|
||||
case 2: statusText += QString(" (Err 5 VA)"); break;
|
||||
case 3: statusText += QString(" (Err 5 Vsci)"); break;
|
||||
case 4: statusText += QString(" (Err 24 V)"); break;
|
||||
case 5: statusText += QString(" (Hardfault)"); break;
|
||||
case 6: statusText += QString(" (Empty Settings)"); break;
|
||||
case 7: statusText += QString(" (ADC Error)"); break;
|
||||
case 8: statusText += QString(" (Program Err 4)"); break;
|
||||
case 9: statusText += QString(" (Program Err 5)"); break;
|
||||
case 10: statusText += QString(" (EEPROM Error)"); break;
|
||||
case 11: statusText += QString(" (Unstable discharge)"); break;
|
||||
case 12: statusText += QString(" (RS/UART Errors)"); break;
|
||||
default: statusText += QString(" (Program Err %1)").arg(numb_err - 4);
|
||||
}
|
||||
}
|
||||
Boards[boardID].localError->setText(statusText);
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include "multiplesettings.h"
|
||||
#include "scanboard.h"
|
||||
#include "lineringer.h"
|
||||
#include "parameterworkspace.h"
|
||||
|
||||
#include <QModbusTcpClient>
|
||||
#include <QModbusRtuSerialMaster>
|
||||
@ -65,8 +66,6 @@ private:
|
||||
void applySettingsFromScan(QModbusReply *reply);
|
||||
void multipleRegWrite();
|
||||
void multipleRegSend();
|
||||
void writeSingleCoil(int boardId, int coilAddress, bool value);
|
||||
void writeSingleRegister(int boardId, int regAddress, quint16 value);
|
||||
bool autoBaudRateScan();
|
||||
void selectPositionOnTree(unsigned index);
|
||||
signals:
|
||||
@ -95,6 +94,8 @@ public:
|
||||
~M3KTE();
|
||||
QModbusClient* getModbusDevice() const { return modbusDevice; }
|
||||
QModbusReply* readSingleCoil(int boardID, int coilAddress);
|
||||
void writeSingleCoil(int boardId, int coilAddress, bool value);
|
||||
void writeSingleRegister(int boardId, int regAddress, quint16 value);
|
||||
private:
|
||||
Ui::M3KTE *ui;
|
||||
QTableWidget *loggerTable = nullptr;
|
||||
@ -107,6 +108,7 @@ private:
|
||||
DebugTerminalDialog *m_debugTerminalDialog = nullptr;
|
||||
SettingsDialog *m_settingsDialog = nullptr;
|
||||
MultipleSettings *m_regMultipleSettings = nullptr;
|
||||
ParameterWorkspace *m_parameterWorkspace = nullptr;
|
||||
ScanBoard *m_scanBoard = nullptr;
|
||||
LineRinger *m_lineRinger = nullptr;
|
||||
QGroupBox *Boards_Fields[4];
|
||||
|
||||
@ -14643,6 +14643,7 @@
|
||||
<string>Модули</string>
|
||||
</property>
|
||||
<addaction name="LineCall"/>
|
||||
<addaction name="ParameterScan"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="DebugMenu">
|
||||
<property name="title">
|
||||
@ -14691,11 +14692,37 @@
|
||||
<property name="text">
|
||||
<string>Открыть</string>
|
||||
</property>
|
||||
<property name="iconVisibleInMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="shortcutVisibleInContextMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="OpenADCBuff">
|
||||
<property name="text">
|
||||
<string>Буфер АЦП</string>
|
||||
</property>
|
||||
<property name="iconVisibleInMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="shortcutVisibleInContextMenu">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="ParameterScan">
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Сканировать параметры</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
||||
56
M3KTE_TERM/parameterbox.cpp
Normal file
56
M3KTE_TERM/parameterbox.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
#include "parameterbox.h"
|
||||
#include "ui_parameterbox.h"
|
||||
|
||||
ParameterBox::ParameterBox(QWidget *parent, pboxMode Mode, quint16 objectID) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::ParameterBox)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
boxMode = Mode;
|
||||
ID = objectID;
|
||||
switch (boxMode) {
|
||||
case Info:
|
||||
ui->adrLine->setHidden(true);
|
||||
ui->valueBox->setHidden(true);
|
||||
ui->sendButton->setHidden(true);
|
||||
break;
|
||||
case MTemplate:
|
||||
break;
|
||||
}
|
||||
|
||||
ui->objectIdLabel->setText("0x" + QString::number(ID, 16));
|
||||
}
|
||||
|
||||
ParameterBox::~ParameterBox()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ParameterBox::on_sendButton_clicked()
|
||||
{
|
||||
if(ui->valueBox->currentText().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
emit writeParameter(ui->adrLine->text().toInt(), ui->valueBox->currentText().toInt(nullptr, 16));
|
||||
}
|
||||
|
||||
void ParameterBox::setData(QString data)
|
||||
{
|
||||
ui->nameLine->setText(data);
|
||||
}
|
||||
|
||||
void ParameterBox::setData(QString name, QString adr, QStringList values)
|
||||
{
|
||||
switch (boxMode) {
|
||||
case Info:
|
||||
ui->nameLine->setText(name);
|
||||
break;
|
||||
case MTemplate:
|
||||
ui->nameLine->setText(name);
|
||||
ui->adrLine->setText(adr);
|
||||
ui->valueBox->clear();
|
||||
ui->valueBox->addItems(values);
|
||||
break;
|
||||
}
|
||||
}
|
||||
43
M3KTE_TERM/parameterbox.h
Normal file
43
M3KTE_TERM/parameterbox.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef PARAMETERBOX_H
|
||||
#define PARAMETERBOX_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class ParameterBox;
|
||||
}
|
||||
|
||||
class ParameterBox : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum pboxMode{
|
||||
Info = 0,
|
||||
MTemplate = 1
|
||||
};
|
||||
enum objectType{
|
||||
Coil = 0,
|
||||
HR = 1
|
||||
};
|
||||
|
||||
explicit ParameterBox(QWidget *parent = nullptr, pboxMode Mode = Info, quint16 objectID = 0x80);
|
||||
~ParameterBox();
|
||||
|
||||
void setData(QString data);
|
||||
void setData(QString name, QString adr, QStringList values);
|
||||
quint16 getID(){return ID;}
|
||||
objectType getType(){return type;}
|
||||
signals:
|
||||
void writeParameter(int adr, quint16 value);
|
||||
private slots:
|
||||
void on_sendButton_clicked();
|
||||
|
||||
private:
|
||||
quint16 ID;
|
||||
pboxMode boxMode;
|
||||
objectType type = HR;
|
||||
Ui::ParameterBox *ui;
|
||||
};
|
||||
|
||||
#endif // PARAMETERBOX_H
|
||||
86
M3KTE_TERM/parameterbox.ui
Normal file
86
M3KTE_TERM/parameterbox.ui
Normal file
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ParameterBox</class>
|
||||
<widget class="QWidget" name="ParameterBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>43</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="adrLine">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="sendButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SEND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="nameLine">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QComboBox" name="valueBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="objectIdLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
151
M3KTE_TERM/parameterdevice.cpp
Normal file
151
M3KTE_TERM/parameterdevice.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
#include "parameterdevice.h"
|
||||
#include "ui_parameterdevice.h"
|
||||
|
||||
void sortParameterBoxesByID(QVector<ParameterBox*>& parameterBoxes) {
|
||||
std::sort(parameterBoxes.begin(), parameterBoxes.end(),
|
||||
[](ParameterBox* a, ParameterBox* b) {
|
||||
return a->getID() < b->getID();
|
||||
});
|
||||
}
|
||||
|
||||
ParameterDevice::ParameterDevice(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::ParameterDevice)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
updateTimer = new QTimer(this);
|
||||
updateTimer->setSingleShot(true);
|
||||
connect(updateTimer, &QTimer::timeout, this, &ParameterDevice::sortScrollArea);
|
||||
}
|
||||
|
||||
ParameterDevice::~ParameterDevice()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ParameterDevice::on_selectiveRadio_clicked()
|
||||
{
|
||||
ui->selectiveBox->setEnabled(true);
|
||||
mode = selectiveRequest;
|
||||
}
|
||||
|
||||
void ParameterDevice::on_fullRadio_clicked()
|
||||
{
|
||||
ui->selectiveBox->setEnabled(false);
|
||||
mode = fullRequest;
|
||||
}
|
||||
|
||||
void ParameterDevice::on_checkButton_clicked()
|
||||
{
|
||||
for (ParameterBox* box : parameterBoxes) {
|
||||
if (box) {
|
||||
box->deleteLater();
|
||||
}
|
||||
}
|
||||
parameterBoxes.clear();
|
||||
quint16 strAdr;
|
||||
int cnt;
|
||||
strAdr = ui->adrSpin->value();
|
||||
switch (mode) {
|
||||
case fullRequest:
|
||||
strAdr = 0x80;
|
||||
cnt = 128;
|
||||
break;
|
||||
case selectiveRequest:
|
||||
cnt = ui->countSpin->value();
|
||||
break;
|
||||
}
|
||||
QProgressDialog progressDialog("Обработка...", "Отмена", 0, cnt, this);
|
||||
progressDialog.setWindowModality(Qt::WindowModal);
|
||||
progressDialog.setMinimumDuration(0); // показывать сразу
|
||||
QEventLoop loop;
|
||||
connect(this, &ParameterDevice::transmitEnd, &loop, &QEventLoop::quit);
|
||||
for (int i = 0; i < cnt; i ++) {
|
||||
// Обновляем прогресс
|
||||
progressDialog.setValue(i);
|
||||
if (progressDialog.wasCanceled()) {
|
||||
break; // пользователь отменил
|
||||
}
|
||||
QByteArray data = QByteArray::fromHex("0E04");
|
||||
data.append(strAdr+i);
|
||||
QModbusRequest request(QModbusRequest::EncapsulatedInterfaceTransport, data);
|
||||
emit read(request, strAdr+i);
|
||||
loop.exec();
|
||||
if(errorAtTransmit)
|
||||
{
|
||||
errorAtTransmit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
progressDialog.setValue(cnt);
|
||||
sortParameterBoxesByID(parameterBoxes);
|
||||
sortScrollArea();
|
||||
}
|
||||
|
||||
void ParameterDevice::setError(QString error)
|
||||
{
|
||||
|
||||
QMessageBox::information(nullptr, "Получен ответ", error);
|
||||
errorAtTransmit = true;
|
||||
emit transmitEnd();
|
||||
}
|
||||
|
||||
void ParameterDevice::on_adrSpin_valueChanged(int arg1)
|
||||
{
|
||||
ui->countSpin->setRange(1, 256-arg1);
|
||||
}
|
||||
|
||||
void ParameterDevice::setAnswer(QString reply, quint16 objectID)
|
||||
{
|
||||
ParameterBox *newbox = new ParameterBox(nullptr, ParameterBox::Info, objectID);
|
||||
newbox->setData(reply);
|
||||
switch (newbox->getType()) {
|
||||
case ParameterBox::Coil:
|
||||
connect(newbox, &ParameterBox::writeParameter, this, [this](int adr, quint16 value){
|
||||
emit writeSingleCoil(adr, (bool)value);
|
||||
});
|
||||
break;
|
||||
case ParameterBox::HR:
|
||||
connect(newbox, &ParameterBox::writeParameter, this, [this](int adr, quint16 value){
|
||||
emit writeSingleRegister(adr, value);
|
||||
});
|
||||
break;
|
||||
}
|
||||
parameterBoxes.append(newbox);
|
||||
emit transmitEnd();
|
||||
|
||||
// // Остановить, если уже запущен
|
||||
// if (updateTimer->isActive()) {
|
||||
// updateTimer->stop();
|
||||
// }
|
||||
// // Запустить с задержкой 6 секунд
|
||||
// updateTimer->start(6000);
|
||||
}
|
||||
|
||||
void ParameterDevice::sortScrollArea()
|
||||
{
|
||||
//sortParameterBoxesByID(parameterBoxes);
|
||||
//ui->parameterBoxHubContents->layout()->deleteLater();
|
||||
QLayout* pblayout = ui->parameterBoxHubContents->layout();
|
||||
if (!pblayout) {
|
||||
// Создайте новый лейаут, если его нет
|
||||
pblayout = new QVBoxLayout(ui->parameterBoxHubContents);
|
||||
ui->parameterBoxHubContents->setLayout(pblayout);
|
||||
}
|
||||
QLayoutItem *item;
|
||||
while ((item = pblayout->takeAt(0)) != nullptr){
|
||||
//delete item;
|
||||
}
|
||||
|
||||
//ui->parameterBoxHubContents->setLayout(pblayout);
|
||||
|
||||
for (int i = 0; i < parameterBoxes.count(); i++) {
|
||||
pblayout->addWidget(parameterBoxes.at(i));
|
||||
}
|
||||
|
||||
ui->parameterBoxHubContents->update();
|
||||
ui->parameterBoxHubContents->adjustSize();
|
||||
ui->scrollArea->updateGeometry();
|
||||
ui->scrollArea->viewport()->update();
|
||||
}
|
||||
62
M3KTE_TERM/parameterdevice.h
Normal file
62
M3KTE_TERM/parameterdevice.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef ParameterDevice_H
|
||||
#define ParameterDevice_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QModbusRequest>
|
||||
#include "parameterbox.h"
|
||||
#include <algorithm>
|
||||
#include <QLayout>
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
|
||||
void sortParameterBoxesByID(QVector<ParameterBox*>& parameterBoxes);
|
||||
|
||||
namespace Ui {
|
||||
class ParameterDevice;
|
||||
}
|
||||
|
||||
class ParameterDevice : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum requestMode{
|
||||
fullRequest = 0,
|
||||
selectiveRequest = 1
|
||||
};
|
||||
void setAnswer(QString reply, quint16 objectID);
|
||||
void setError(QString error);
|
||||
void setAdr(int _adr){adr = _adr;}
|
||||
int getAdr(){return adr;}
|
||||
bool errorAtTransmit = false;
|
||||
explicit ParameterDevice(QWidget *parent = nullptr);
|
||||
~ParameterDevice();
|
||||
signals:
|
||||
void read(QModbusRequest request, quint16 objectID);
|
||||
void writeSingleCoil(int coilAddress, bool value);
|
||||
void writeSingleRegister(int registerAddress, quint16 value);
|
||||
void transmitEnd();
|
||||
|
||||
private slots:
|
||||
void on_selectiveRadio_clicked();
|
||||
|
||||
void on_fullRadio_clicked();
|
||||
|
||||
void on_checkButton_clicked();
|
||||
|
||||
void on_adrSpin_valueChanged(int arg1);
|
||||
|
||||
private:
|
||||
void sortScrollArea();
|
||||
|
||||
private:
|
||||
int adr;
|
||||
QTimer *updateTimer;
|
||||
QVector<ParameterBox*>parameterBoxes;
|
||||
|
||||
requestMode mode = fullRequest;
|
||||
Ui::ParameterDevice *ui;
|
||||
};
|
||||
|
||||
#endif // ParameterDevice_H
|
||||
141
M3KTE_TERM/parameterdevice.ui
Normal file
141
M3KTE_TERM/parameterdevice.ui
Normal file
@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ParameterDevice</class>
|
||||
<widget class="QWidget" name="ParameterDevice">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>687</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Extended Objects</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="1">
|
||||
<widget class="QGroupBox" name="selectiveBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="adrSpin">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string>0x</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
<property name="displayIntegerBase">
|
||||
<number>16</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start Adr:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Count:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="countSpin">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QRadioButton" name="selectiveRadio">
|
||||
<property name="text">
|
||||
<string>Selective Request</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="checkButton">
|
||||
<property name="text">
|
||||
<string>Check</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QRadioButton" name="fullRadio">
|
||||
<property name="text">
|
||||
<string>Full Request</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="parameterBoxHubContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>380</width>
|
||||
<height>450</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
124
M3KTE_TERM/parameterworkspace.cpp
Normal file
124
M3KTE_TERM/parameterworkspace.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include "parameterworkspace.h"
|
||||
#include "ui_parameterworkspace.h"
|
||||
|
||||
ParameterWorkspace::ParameterWorkspace(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::ParameterWorkspace)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
}
|
||||
|
||||
ParameterWorkspace::~ParameterWorkspace()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
// QModbusRequest requestOfDeviceType(QModbusRequest::EncapsulatedInterfaceTransport, QByteArray::fromHex("0E0404"));
|
||||
// auto *reply = modbusDevice->sendRawRequest(requestOfDeviceType, tmp_adr);
|
||||
void ParameterWorkspace::setDeviceCount(int count)
|
||||
{
|
||||
for(const auto& device : deviceList)
|
||||
{
|
||||
device.tab->deleteLater();
|
||||
device.device->deleteLater();
|
||||
}
|
||||
deviceList.clear();
|
||||
for(int i = 0; i < ui->tabWidget->count(); i++)
|
||||
ui->tabWidget->removeTab(i);
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
device* _device = new device();
|
||||
deviceList.append(*_device);
|
||||
deviceList[i].device = new ParameterDevice();
|
||||
int newtab = ui->tabWidget->addTab(deviceList[i].device, tr("Device №%1").arg(i+1));
|
||||
deviceList[i].tab = ui->tabWidget->widget(newtab);
|
||||
connect(deviceList[i].device, &ParameterDevice::read, this, [this, i](QModbusRequest request, quint16 objectID){
|
||||
readDeviceIdentification(deviceList[i].device, request, deviceList[i].adr, objectID);
|
||||
});
|
||||
connect(deviceList[i].device, &ParameterDevice::writeSingleCoil, this, [this, i](int coilAddress, bool value){
|
||||
writeSingleCoil(deviceList[i].adr, coilAddress, value);
|
||||
});
|
||||
connect(deviceList[i].device, &ParameterDevice::writeSingleRegister, this, [this, i](int registerAddress, quint16 value){
|
||||
writeSingleRegister(deviceList[i].adr, registerAddress, value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterWorkspace::writeSingleCoil(int adr, int coilAddress, bool value)
|
||||
{
|
||||
if (!modbusDevice && modbusDevice->state() == QModbusDevice::ConnectedState)
|
||||
return;
|
||||
QModbusDataUnit unit(QModbusDataUnit::Coils, coilAddress, 1);
|
||||
unit.setValue(0, value ? 1 : 0);
|
||||
if (auto *reply = modbusDevice->sendWriteRequest(unit, adr)) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply]() {
|
||||
if (reply->error() != QModbusDevice::NoError) {
|
||||
//ERROR
|
||||
}
|
||||
reply->deleteLater();
|
||||
});
|
||||
} else {
|
||||
reply->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterWorkspace::writeSingleRegister(int adr, int regAddress, quint16 value)
|
||||
{
|
||||
if (!modbusDevice && modbusDevice->state() == QModbusDevice::ConnectedState)
|
||||
return;
|
||||
QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, regAddress, 1);
|
||||
unit.setValue(0, value);
|
||||
if (auto *reply = modbusDevice->sendWriteRequest(unit, adr)) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply]() {
|
||||
if (reply->error() != QModbusDevice::NoError) {
|
||||
//ERROR
|
||||
}
|
||||
reply->deleteLater();
|
||||
});
|
||||
} else {
|
||||
reply->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterWorkspace::readDeviceIdentification(ParameterDevice *device, QModbusRequest request, int adr, quint16 objectID)
|
||||
{
|
||||
if (!modbusDevice && modbusDevice->state() == QModbusDevice::ConnectedState)
|
||||
return;
|
||||
if(auto *reply = modbusDevice->sendRawRequest(request, adr))
|
||||
{
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, this, [this, device, reply, objectID](){
|
||||
if(reply->error() == QModbusDevice::NoError)
|
||||
{
|
||||
QModbusResponse resp = reply->rawResult();
|
||||
if(resp.data().size() >= MODBUS_REQUEST_PROTOCOL_INFO_LENGTH)
|
||||
{
|
||||
QString result = QString(resp.data().remove(0, MODBUS_REQUEST_PROTOCOL_INFO_LENGTH));
|
||||
device->setAnswer(result, objectID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
device->setError(reply->errorString());
|
||||
qDebug()<<"Получен ответ:" + reply->errorString();
|
||||
}
|
||||
reply->deleteLater();
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
device->setError("Unknow error");
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterWorkspace::updateDevice(int ID, bool status, int adr)
|
||||
{
|
||||
deviceList[ID].isActive = status;
|
||||
deviceList[ID].adr = adr;
|
||||
deviceList[ID].device->setAdr(adr);
|
||||
}
|
||||
53
M3KTE_TERM/parameterworkspace.h
Normal file
53
M3KTE_TERM/parameterworkspace.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef PARAMETERWORKSPACE_H
|
||||
#define PARAMETERWORKSPACE_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDebug>
|
||||
#include <QModbusRequest>
|
||||
#include <QModbusDataUnit>
|
||||
#include <QModbusTcpClient>
|
||||
#include <QModbusRtuSerialMaster>
|
||||
#include <QtSerialBus/qtserialbusglobal.h>
|
||||
|
||||
#if QT_CONFIG(modbus_serialport)
|
||||
#include <QSerialPort>
|
||||
#endif
|
||||
|
||||
#include "parameterdevice.h"
|
||||
|
||||
#define MODBUS_REQUEST_PROTOCOL_INFO_LENGTH 8
|
||||
|
||||
namespace Ui {
|
||||
class ParameterWorkspace;
|
||||
}
|
||||
|
||||
class ParameterWorkspace : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ParameterWorkspace(QWidget *parent = nullptr);
|
||||
~ParameterWorkspace();
|
||||
public:
|
||||
void setModbusClient(QModbusClient *device){modbusDevice = device;}
|
||||
void setDeviceCount(int count);
|
||||
void updateDevice(int deviceID, bool status, int adr);
|
||||
|
||||
private slots:
|
||||
void readDeviceIdentification(ParameterDevice *board, QModbusRequest request, int adr, quint16 objectID);
|
||||
void writeSingleCoil(int adr, int coilAddress, bool value);
|
||||
void writeSingleRegister(int adr, int registerAddress, quint16 value);
|
||||
|
||||
private:
|
||||
struct device{
|
||||
bool isActive = false;
|
||||
int adr = 1;
|
||||
ParameterDevice *device = nullptr;
|
||||
QWidget *tab = nullptr;
|
||||
};
|
||||
QVector<device> deviceList;
|
||||
QModbusClient *modbusDevice = nullptr;
|
||||
Ui::ParameterWorkspace *ui;
|
||||
};
|
||||
|
||||
#endif // PARAMETERWORKSPACE_H
|
||||
31
M3KTE_TERM/parameterworkspace.ui
Normal file
31
M3KTE_TERM/parameterworkspace.ui
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ParameterWorkspace</class>
|
||||
<widget class="QWidget" name="ParameterWorkspace">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>610</width>
|
||||
<height>646</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="tabPosition">
|
||||
<enum>QTabWidget::North</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Loading…
Reference in New Issue
Block a user