Hightlight lines when touched.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE QtCreatorProject>
|
<!DOCTYPE QtCreatorProject>
|
||||||
<!-- Written by QtCreator 18.0.1, 2025-12-19T10:26:05. -->
|
<!-- Written by QtCreator 18.0.1, 2025-12-19T17:13:02. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
|
|||||||
@@ -2,6 +2,5 @@
|
|||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file alias="bikeinfo.xml">data/bikeinfo.xml</file>
|
<file alias="bikeinfo.xml">data/bikeinfo.xml</file>
|
||||||
<file>bionxcontrol.qss</file>
|
<file>bionxcontrol.qss</file>
|
||||||
<file alias="typeinfo.xml">data/typeinfo.xml</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -50,22 +50,30 @@ void BCValueModel::setValueList(const BCValueList& valueList)
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BCValueList& BCValueModel::getValueList()
|
||||||
|
{
|
||||||
|
return _valueList;
|
||||||
|
}
|
||||||
|
|
||||||
int BCValueModel::rowCount(const QModelIndex &parent) const
|
int BCValueModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (parent.isValid()) return 0;
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
return _valueList.size();
|
return _valueList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant BCValueModel::data(const QModelIndex &index, int role) const
|
QVariant BCValueModel::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
if (!index.isValid() || index.row() >= _valueList.size())
|
int row = index.row();
|
||||||
|
if (!index.isValid() || row >= _valueList.size())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
const BCValue &item = _valueList.at(index.row());
|
BCValue& value = const_cast<BCValue&>(_valueList.at( row ));
|
||||||
|
value.rowInModel = row;
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||||
|
return QVariant::fromValue(value);
|
||||||
|
|
||||||
if (role == Qt::DisplayRole || role == Qt::EditRole) {
|
|
||||||
return QVariant::fromValue(item);
|
|
||||||
}
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ public:
|
|||||||
|
|
||||||
void addValue(const BCValue &val);
|
void addValue(const BCValue &val);
|
||||||
void setValueList(const BCValueList& valueList);
|
void setValueList(const BCValueList& valueList);
|
||||||
|
BCValueList& getValueList();
|
||||||
|
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|||||||
@@ -3,14 +3,17 @@
|
|||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QListView>
|
||||||
|
|
||||||
#include "bcitemdelegate.h"
|
#include "bcitemdelegate.h"
|
||||||
#include "bcvalue.h"
|
#include "bcvalue.h"
|
||||||
#include "qapplication.h"
|
#include "qapplication.h"
|
||||||
|
|
||||||
|
|
||||||
BCItemDelegate::BCItemDelegate(QObject *parent)
|
BCItemDelegate::BCItemDelegate(QListView *view)
|
||||||
: QStyledItemDelegate(parent)
|
: QStyledItemDelegate(view), _view{view}
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -26,7 +29,7 @@ QString BCItemDelegate::displayText(const QVariant& dataValue, const QLocale& lo
|
|||||||
// Hier bauen wir den String zusammen, den man sieht,
|
// Hier bauen wir den String zusammen, den man sieht,
|
||||||
// wenn KEIN Editor offen ist.
|
// wenn KEIN Editor offen ist.
|
||||||
// Format: "Label: Wert Einheit"
|
// Format: "Label: Wert Einheit"
|
||||||
return QString("%1: %2 %3").arg(bc.label, bc.value.toString(), "mm1");
|
return QString("%1: %2 %3").arg(bc.label, bc.value.toString(), "mmX");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback für normale Strings/Zahlen
|
// Fallback für normale Strings/Zahlen
|
||||||
@@ -132,6 +135,51 @@ QSize BCItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelI
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BCItemDelegate::onHighlightRow(int row)
|
||||||
|
{
|
||||||
|
qDebug() << " --- should highlight: " << row;
|
||||||
|
_highlightedRow = row;
|
||||||
|
|
||||||
|
// Trigger Repaint der View (damit der Rahmen sofort erscheint)
|
||||||
|
_view->viewport()->update();
|
||||||
|
|
||||||
|
// Timer: Nach 1 Sekunde wieder ausschalten (Temporär)
|
||||||
|
QTimer::singleShot(1000, this, [=, this]()
|
||||||
|
{
|
||||||
|
if(_highlightedRow == row)
|
||||||
|
{ // Nur zurücksetzen, wenn es noch dieselbe Zeile ist
|
||||||
|
_highlightedRow = -1;
|
||||||
|
if (_view)
|
||||||
|
_view->viewport()->update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void BCItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
// 1. Standard-Zeichnen (Text, Hintergrund, Selection) durchführen
|
||||||
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
|
||||||
|
// 2. Unser Custom-Overly: Oranger Rahmen, wenn Zeile passt
|
||||||
|
if (index.row() == _highlightedRow)
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
qDebug() << " --- is highlight: " << index.row();
|
||||||
|
|
||||||
|
// Setup Stift
|
||||||
|
QPen pen(QColor(255, 165, 0)); // Orange
|
||||||
|
pen.setWidth(2);
|
||||||
|
painter->setPen(pen);
|
||||||
|
|
||||||
|
// Rechteck zeichnen (leicht eingezogen, damit es nicht abgeschnitten wird)
|
||||||
|
QRect rect = option.rect.adjusted(1, 1, -1, -1);
|
||||||
|
painter->drawRect(rect);
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
QString BCItemDelegate::formatDisplayString(const QModelIndex &index) const
|
QString BCItemDelegate::formatDisplayString(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
|
|||||||
@@ -2,18 +2,18 @@
|
|||||||
#ifndef BCITEMDELEGATE_H
|
#ifndef BCITEMDELEGATE_H
|
||||||
#define BCITEMDELEGATE_H
|
#define BCITEMDELEGATE_H
|
||||||
|
|
||||||
|
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
|
class QListView;
|
||||||
|
|
||||||
class BCItemDelegate : public QStyledItemDelegate
|
class BCItemDelegate : public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit BCItemDelegate(QObject *parent = nullptr);
|
explicit BCItemDelegate(QListView *view );
|
||||||
|
|
||||||
// WICHTIG: Zuständig für die normale Anzeige (ohne Editor)
|
|
||||||
QString displayText(const QVariant& dataValue, const QLocale& locale) const override;
|
QString displayText(const QVariant& dataValue, const QLocale& locale) const override;
|
||||||
|
|
||||||
// Zuständig für den Edit-Modus (Doppelklick)
|
// Zuständig für den Edit-Modus (Doppelklick)
|
||||||
@@ -23,9 +23,19 @@ public:
|
|||||||
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
|
||||||
QSize sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const override;
|
QSize sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const override;
|
||||||
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void onHighlightRow(int row);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QString formatDisplayString(const QModelIndex &index) const;
|
QString formatDisplayString(const QModelIndex &index) const;
|
||||||
|
|
||||||
|
int _highlightedRow{-1};
|
||||||
|
QListView* _view{nullptr};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,12 +36,16 @@ BCMainWindow::BCMainWindow(QWidget *parent)
|
|||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
_valueManager.loadBikeData();
|
_valueManager.loadBikeData();
|
||||||
auto model = _valueManager.getModel( "Console"_L1 );
|
auto model = _valueManager.getModel( BCDevice::ID::Console );
|
||||||
if( model)
|
if( model)
|
||||||
_valueView->setModel( *model );
|
_valueView->setModel( *model );
|
||||||
_valueView->setItemDelegate( new BCItemDelegate( _valueView) );
|
|
||||||
|
|
||||||
|
BCItemDelegate* delegate = new BCItemDelegate( _valueView);
|
||||||
|
_valueView->setItemDelegate( delegate );
|
||||||
|
|
||||||
|
connect( &_valueManager, &BCValueManager::valueTouched, delegate, &BCItemDelegate::onHighlightRow );
|
||||||
connect( _connectButton, &QPushButton::clicked, &_valueManager, &BCValueManager::onToggleConnectionState );
|
connect( _connectButton, &QPushButton::clicked, &_valueManager, &BCValueManager::onToggleConnectionState );
|
||||||
|
connect( _syncButton, &QPushButton::clicked, &_valueManager, &BCValueManager::onSyncFromDevice );
|
||||||
}
|
}
|
||||||
|
|
||||||
BCMainWindow::~BCMainWindow()
|
BCMainWindow::~BCMainWindow()
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<property name="frameShadow">
|
<property name="frameShadow">
|
||||||
<enum>QFrame::Shadow::Raised</enum>
|
<enum>QFrame::Shadow::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QPushButton" name="_pushButton">
|
<widget class="QPushButton" name="_syncButton">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>30</x>
|
<x>30</x>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>PushButton</string>
|
<string>Sync</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPushButton" name="_connectButton">
|
<widget class="QPushButton" name="_connectButton">
|
||||||
|
|||||||
@@ -106,9 +106,8 @@ public:
|
|||||||
|
|
||||||
BCDevice::ID deviceID{BCDevice::ID::Invalid};
|
BCDevice::ID deviceID{BCDevice::ID::Invalid};
|
||||||
BC::ID targetID{BC::ID::Invalid};
|
BC::ID targetID{BC::ID::Invalid};
|
||||||
|
|
||||||
BCValueType::TypeID typeID{BCValueType::TypeID::Invalid};;
|
BCValueType::TypeID typeID{BCValueType::TypeID::Invalid};;
|
||||||
|
int rowInModel{-1};
|
||||||
QString label;
|
QString label;
|
||||||
QVariant value;
|
QVariant value;
|
||||||
QVariant defaultValue;
|
QVariant defaultValue;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QStatusBar>
|
#include <QStatusBar>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
#include <bcvaluemanager.h>
|
#include <bcvaluemanager.h>
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ BCValueManager::BCValueManager(QObject *parent)
|
|||||||
// 4. Verbindungen herstellen (Signal/Slot über Thread-Grenzen)
|
// 4. Verbindungen herstellen (Signal/Slot über Thread-Grenzen)
|
||||||
|
|
||||||
// A) Befehl senden (Manager -> Runner)
|
// A) Befehl senden (Manager -> Runner)
|
||||||
connect(this, &BCValueManager::newCommandArrived, &_transmitter, &BCTransmitter::addCommand);
|
connect(this, &BCValueManager::newCommandArrived, &_transmitter, &BCTransmitter::enqueueValue);
|
||||||
|
|
||||||
// B) Ergebnisse empfangen (Runner -> Manager)
|
// B) Ergebnisse empfangen (Runner -> Manager)
|
||||||
connect(&_transmitter, &BCTransmitter::commandFinished, this, &BCValueManager::onCommandFinished);
|
connect(&_transmitter, &BCTransmitter::commandFinished, this, &BCValueManager::onCommandFinished);
|
||||||
@@ -136,11 +137,31 @@ void BCValueManager::onToggleConnectionState( bool connect )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BCValueManager::onSyncFromDevice()
|
||||||
std::optional<BCValueModel*> BCValueManager::getModel(const QString& key )
|
|
||||||
{
|
{
|
||||||
if( _valueModels.contains( key) )
|
qDebug() << " ---Syncing";
|
||||||
return _valueModels[key];
|
if( _currentDeviceID != BCDevice::ID::Invalid)
|
||||||
|
{
|
||||||
|
|
||||||
|
BCValueList& currentList = _valueModels[_currentDeviceID]->getValueList();
|
||||||
|
for( BCValue& value : currentList )
|
||||||
|
{
|
||||||
|
qDebug() << " --- value: " << value.label;
|
||||||
|
_transmitter.enqueueValue( value );
|
||||||
|
emit valueTouched( value.rowInModel );
|
||||||
|
QApplication::processEvents();
|
||||||
|
// Thread schlafen lassen (Simulation einer blockierenden Operation)
|
||||||
|
QThread::msleep(500);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<BCValueModel*> BCValueManager::getModel(BCDevice::ID deviceID )
|
||||||
|
{
|
||||||
|
if( _valueModels.contains( deviceID) )
|
||||||
|
return _valueModels[deviceID];
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,25 +206,28 @@ void BCValueManager::loadBikeData()
|
|||||||
if (token == QXmlStreamReader::StartElement)
|
if (token == QXmlStreamReader::StartElement)
|
||||||
{
|
{
|
||||||
QString deviceType = _xml.attributes().value("Type"_L1).toString();
|
QString deviceType = _xml.attributes().value("Type"_L1).toString();
|
||||||
qDebug() << " --- Device: " << _xml.name() << ": " << deviceType;
|
|
||||||
printAttrs (_xml);
|
printAttrs (_xml);
|
||||||
const char* deviceKey = _xml.attributes().value("Type"_L1).toLatin1().constData();
|
const char* deviceKey = _xml.attributes().value("Type"_L1).toLatin1().constData();
|
||||||
auto deviceID = _bcDeviceEnum.keyToValue64(deviceKey);
|
auto deviceID = _bcDeviceEnum.keyToValue64(deviceKey);
|
||||||
//_currentDeviceID = BCDevice::ID( deviceID.value_or( BCDevice::ID::Invalid ) );
|
//_currentDeviceID = BCDevice::ID( deviceID.value_or( BCDevice::ID::Invalid ) );
|
||||||
_currentDeviceID = deviceID.has_value() ? BCDevice::ID( deviceID.value() ) : BCDevice::ID::Invalid;
|
|
||||||
if(deviceID.has_value())
|
if(deviceID.has_value())
|
||||||
{
|
{
|
||||||
BCValueList parsedValues;
|
qDebug() << " --- Device: " << _xml.name() << ": " << deviceType << " : " << deviceID;
|
||||||
|
|
||||||
|
_currentDeviceID = BCDevice::ID( deviceID.value() );
|
||||||
|
BCValueList parsedValues;
|
||||||
loadDeviceData( parsedValues );
|
loadDeviceData( parsedValues );
|
||||||
if( parsedValues.count() )
|
if( parsedValues.count() )
|
||||||
{
|
{
|
||||||
BCValueModel* valueModel = new BCValueModel( this );
|
BCValueModel* valueModel = new BCValueModel( this );
|
||||||
valueModel->setValueList(parsedValues);
|
valueModel->setValueList(parsedValues);
|
||||||
_valueModels.insert( deviceType, valueModel );
|
_valueModels.insert( _currentDeviceID, valueModel );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_currentDeviceID = BCDevice::ID::Console;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
BCValueManager( QObject* parent = nullptr);
|
BCValueManager( QObject* parent = nullptr);
|
||||||
virtual ~BCValueManager();
|
virtual ~BCValueManager();
|
||||||
|
|
||||||
std::optional<BCValueModel*> getModel(const QString& key );
|
std::optional<BCValueModel*> getModel(BCDevice::ID deviceID );
|
||||||
|
|
||||||
BCValue makeValue(BCDevice::ID deviceID, const BCValueParams& params );
|
BCValue makeValue(BCDevice::ID deviceID, const BCValueParams& params );
|
||||||
|
|
||||||
@@ -62,11 +62,14 @@ public slots:
|
|||||||
void loadBikeData();
|
void loadBikeData();
|
||||||
void saveBikeData();
|
void saveBikeData();
|
||||||
void onToggleConnectionState( bool connect );
|
void onToggleConnectionState( bool connect );
|
||||||
|
void onSyncFromDevice();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
// Internes Signal, um Daten an den Worker Thread zu senden
|
// Internes Signal, um Daten an den Worker Thread zu senden
|
||||||
void newCommandArrived(BCValue cmd);
|
void newCommandArrived(const BCValue& cmd);
|
||||||
|
//void valuedTouched(const BCValue& cmd);
|
||||||
|
void valueTouched(int rowInModel );
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
@@ -79,16 +82,19 @@ protected:
|
|||||||
void loadTypeData();
|
void loadTypeData();
|
||||||
void loadDeviceData( BCValueList& parsedValues );
|
void loadDeviceData( BCValueList& parsedValues );
|
||||||
|
|
||||||
QXmlStreamReader _xml;
|
using BCDeviceModels = QMap<BCDevice::ID, BCValueModel*>;
|
||||||
QMap<QString,BCValueType> _valueTypes;
|
using BCValueTypes = QMap<QString,BCValueType>;
|
||||||
QMap<QString,BCValueModel*> _valueModels;
|
|
||||||
BCDevice::ID _currentDeviceID{BCDevice::ID::Invalid};
|
|
||||||
QMetaEnum _bcDeviceEnum{QMetaEnum::fromType<BCDevice::ID>()};
|
|
||||||
|
|
||||||
BCCanDriverTinyCan _canDriver;
|
QXmlStreamReader _xml;
|
||||||
|
BCValueTypes _valueTypes;
|
||||||
|
BCDeviceModels _valueModels;
|
||||||
|
BCDevice::ID _currentDeviceID{BCDevice::ID::Invalid};
|
||||||
|
QMetaEnum _bcDeviceEnum{QMetaEnum::fromType<BCDevice::ID>()};
|
||||||
|
|
||||||
QThread _worker;
|
BCCanDriverTinyCan _canDriver;
|
||||||
BCTransmitter _transmitter;
|
|
||||||
|
QThread _worker;
|
||||||
|
BCTransmitter _transmitter;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user