Finally, animation works.
This commit is contained in:
@@ -7,11 +7,16 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QListView>
|
#include <QListView>
|
||||||
|
|
||||||
|
#include <QVariantAnimation>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
#include "bcitemdelegate.h"
|
#include "bcitemdelegate.h"
|
||||||
#include "bcvalue.h"
|
#include "bcvalue.h"
|
||||||
#include "qapplication.h"
|
#include "qapplication.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BCItemDelegate::BCItemDelegate(QListView *view)
|
BCItemDelegate::BCItemDelegate(QListView *view)
|
||||||
: QStyledItemDelegate(view), _view{view}
|
: QStyledItemDelegate(view), _view{view}
|
||||||
{
|
{
|
||||||
@@ -136,28 +141,9 @@ 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
|
void BCItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
// 1. Standard-Zeichnen (Text, Hintergrund, Selection) durchführen
|
// 1. Standard-Zeichnen (Text, Hintergrund, Selection) durchführen
|
||||||
QStyledItemDelegate::paint(painter, option, index);
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
|
||||||
@@ -179,7 +165,122 @@ void BCItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option
|
|||||||
|
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (index.row() == _highlightedRow && _opacity > 0.0)
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
qDebug() << " --- is highlight: " << index.row();
|
||||||
|
|
||||||
|
QColor highlightColor( 0xFF9800 );
|
||||||
|
highlightColor.setAlphaF(_opacity);
|
||||||
|
|
||||||
|
QPen pen(highlightColor, 3);
|
||||||
|
painter->setPen(pen);
|
||||||
|
painter->setBrush(Qt::NoBrush);
|
||||||
|
painter->drawRoundedRect(option.rect.adjusted(2, 2, -2, -2), 8, 8);
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
int row = index.row();
|
||||||
|
|
||||||
|
if (m_rowOpacities.contains(row))
|
||||||
|
{
|
||||||
|
qreal opacity = m_rowOpacities.value(row);
|
||||||
|
if (opacity > 0.01) {
|
||||||
|
painter->save();
|
||||||
|
painter->setOpacity(opacity);
|
||||||
|
painter->fillRect(option.rect, QColor(255, 140, 0, 120));
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BCItemDelegate::onHighlightRow(int row)
|
||||||
|
{
|
||||||
|
qDebug() << " --- should highlight: " << row;
|
||||||
|
|
||||||
|
// Alte Animation für diese Zeile stoppen falls vorhanden
|
||||||
|
if (m_rowAnimations.contains(row))
|
||||||
|
{
|
||||||
|
m_rowAnimations[row]->stop();
|
||||||
|
m_rowAnimations[row]->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QVariantAnimation ist flexibler als QPropertyAnimation
|
||||||
|
auto* anim = new QVariantAnimation(this);
|
||||||
|
anim->setDuration(800);
|
||||||
|
anim->setStartValue(0.0);
|
||||||
|
anim->setEndValue(1.0);
|
||||||
|
|
||||||
|
// Custom Easing für Fade-in/out Effekt
|
||||||
|
anim->setEasingCurve(QEasingCurve::OutQuad);
|
||||||
|
|
||||||
|
connect(anim, &QVariantAnimation::valueChanged, this, [this, row](const QVariant& value)
|
||||||
|
{
|
||||||
|
qreal progress = value.toReal();
|
||||||
|
qreal opacity;
|
||||||
|
|
||||||
|
// Schnelles Fade-in (20%), langsames Fade-out (80%)
|
||||||
|
if (progress < 0.2) {
|
||||||
|
opacity = progress * 5.0; // 0->1 in 20%
|
||||||
|
} else {
|
||||||
|
opacity = 1.0 - ((progress - 0.2) / 0.8); // 1->0 in 80%
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rowOpacities[row] = opacity;
|
||||||
|
updateRow(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(anim, &QVariantAnimation::finished, this, [this, row, anim]()
|
||||||
|
{
|
||||||
|
m_rowOpacities.remove(row);
|
||||||
|
m_rowAnimations.remove(row);
|
||||||
|
updateRow(row);
|
||||||
|
anim->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_rowAnimations[row] = anim;
|
||||||
|
anim->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: alle Highlights sofort clearen
|
||||||
|
void BCItemDelegate::clearAllHighlights()
|
||||||
|
{
|
||||||
|
for(auto* anim : std::as_const(m_rowAnimations))
|
||||||
|
{
|
||||||
|
anim->stop();
|
||||||
|
anim->deleteLater();
|
||||||
|
}
|
||||||
|
m_rowAnimations.clear();
|
||||||
|
m_rowOpacities.clear();
|
||||||
|
|
||||||
|
if (_view)
|
||||||
|
{
|
||||||
|
_view->viewport()->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BCItemDelegate::updateRow(int row)
|
||||||
|
{
|
||||||
|
if (_view && row >= 0) {
|
||||||
|
QModelIndex idx = _view->model()->index(row, 0);
|
||||||
|
QRect rect = _view->visualRect(idx);
|
||||||
|
if (!rect.isEmpty()) {
|
||||||
|
_view->viewport()->update(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString BCItemDelegate::formatDisplayString(const QModelIndex &index) const
|
QString BCItemDelegate::formatDisplayString(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
|
|||||||
@@ -4,11 +4,14 @@
|
|||||||
|
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
|
class QPropertyAnimation;
|
||||||
|
class QVariantAnimation;
|
||||||
class QListView;
|
class QListView;
|
||||||
|
|
||||||
class BCItemDelegate : public QStyledItemDelegate
|
class BCItemDelegate : public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(qreal highlightOpacity READ highlightOpacity WRITE setHighlightOpacity)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -25,17 +28,45 @@ public:
|
|||||||
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;
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
qreal highlightOpacity() const
|
||||||
|
{
|
||||||
|
return _opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHighlightOpacity(qreal opacity)
|
||||||
|
{
|
||||||
|
_opacity = opacity;
|
||||||
|
//qDebug() << " --- opa: " << opacity;
|
||||||
|
emit viewUpdateNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearAllHighlights();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void onHighlightRow(int row);
|
void onHighlightRow(int row);
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void viewUpdateNeeded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void updateRow(int row);
|
||||||
QString formatDisplayString(const QModelIndex &index) const;
|
QString formatDisplayString(const QModelIndex &index) const;
|
||||||
|
|
||||||
int _highlightedRow{-1};
|
int _highlightedRow{-1};
|
||||||
QListView* _view{nullptr};
|
qreal _opacity{1.0};
|
||||||
|
QListView* _view{};
|
||||||
|
QPropertyAnimation *_animation{};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QHash<int, qreal> m_rowOpacities;
|
||||||
|
QHash<int, QVariantAnimation*> m_rowAnimations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
#include <bcitemdelegate.h>
|
#include <bcitemdelegate.h>
|
||||||
#include <ui_bcmainwindow.h>
|
#include <ui_bcmainwindow.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BCMainWindow::BCMainWindow(QWidget *parent)
|
BCMainWindow::BCMainWindow(QWidget *parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
{
|
{
|
||||||
@@ -40,12 +42,26 @@ BCMainWindow::BCMainWindow(QWidget *parent)
|
|||||||
if( model)
|
if( model)
|
||||||
_valueView->setModel( *model );
|
_valueView->setModel( *model );
|
||||||
|
|
||||||
BCItemDelegate* delegate = new BCItemDelegate( _valueView);
|
BCItemDelegate* _delegate = new BCItemDelegate( _valueView);
|
||||||
_valueView->setItemDelegate( delegate );
|
//_delegate = new AnimatedDelegate(_valueView );
|
||||||
|
_valueView->setItemDelegate( _delegate );
|
||||||
|
|
||||||
connect( &_valueManager, &BCValueManager::valueTouched, delegate, &BCItemDelegate::onHighlightRow );
|
|
||||||
|
// Verwendung:
|
||||||
|
|
||||||
|
connect(_delegate, &BCItemDelegate::viewUpdateNeeded, _valueView->viewport(), QOverload<>::of(&QWidget::update));
|
||||||
|
|
||||||
|
//_valueView->setItemDelegate(_delegate);
|
||||||
|
|
||||||
|
// Highlight mit Fade-Out:
|
||||||
|
_delegate->onHighlightRow(2); // 2 Sekunden Fade
|
||||||
|
|
||||||
|
// besser: model::emit dataChanged
|
||||||
|
// also: emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, ValueRole});
|
||||||
|
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 );
|
connect( _syncButton, &QPushButton::clicked, &_valueManager, &BCValueManager::onSyncFromDevice );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BCMainWindow::~BCMainWindow()
|
BCMainWindow::~BCMainWindow()
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
#include <bcvaluemanager.h>
|
#include <bcvaluemanager.h>
|
||||||
|
|
||||||
|
|
||||||
|
class AnimatedDelegate;
|
||||||
|
|
||||||
class BCMainWindow : public QMainWindow, public Ui_BCMainWindow
|
class BCMainWindow : public QMainWindow, public Ui_BCMainWindow
|
||||||
{
|
{
|
||||||
@@ -54,6 +54,7 @@ public slots:
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
BCValueManager _valueManager;
|
BCValueManager _valueManager;
|
||||||
|
AnimatedDelegate* _delegate;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QStatusBar>
|
#include <QStatusBar>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
#include <bcvaluemanager.h>
|
#include <bcvaluemanager.h>
|
||||||
|
|
||||||
@@ -42,6 +43,16 @@
|
|||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
|
|
||||||
|
void processEventsFor(int milliseconds)
|
||||||
|
{
|
||||||
|
QElapsedTimer timer;
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
while (timer.elapsed() < milliseconds) {
|
||||||
|
QApplication::processEvents(QEventLoop::AllEvents, 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BCValueManager::BCValueManager(QObject *parent)
|
BCValueManager::BCValueManager(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
@@ -54,11 +65,11 @@ 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::enqueueValue);
|
connect(this, &BCValueManager::valueCreated, &_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);
|
||||||
connect(&_transmitter, &BCTransmitter::messageLogged, this, &BCValueManager::onRunnerMessage);
|
//connect(&_transmitter, &BCTransmitter::messageLogged, this, &BCValueManager::onRunnerMessage);
|
||||||
|
|
||||||
// C) Aufräumen: Wenn Thread endet, lösche den Runner
|
// C) Aufräumen: Wenn Thread endet, lösche den Runner
|
||||||
connect(&_worker, &QThread::finished, &_transmitter, &QObject::deleteLater);
|
connect(&_worker, &QThread::finished, &_transmitter, &QObject::deleteLater);
|
||||||
@@ -77,14 +88,6 @@ BCValueManager::~BCValueManager()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BCValueManager::transmitValue(const BCValue& value)
|
|
||||||
{
|
|
||||||
// Wir rufen keine Methode am Runner direkt auf!
|
|
||||||
// Wir emitten ein Signal. Qt kümmert sich um den Thread-Wechsel.
|
|
||||||
|
|
||||||
emit newCommandArrived(value);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void BCValueManager::onCommandFinished(int id, bool success)
|
void BCValueManager::onCommandFinished(int id, bool success)
|
||||||
{
|
{
|
||||||
@@ -144,14 +147,25 @@ void BCValueManager::onSyncFromDevice()
|
|||||||
{
|
{
|
||||||
|
|
||||||
BCValueList& currentList = _valueModels[_currentDeviceID]->getValueList();
|
BCValueList& currentList = _valueModels[_currentDeviceID]->getValueList();
|
||||||
for( BCValue& value : currentList )
|
|
||||||
|
BCValue& value = currentList[4];
|
||||||
|
|
||||||
|
for( const BCValue& value : currentList )
|
||||||
{
|
{
|
||||||
qDebug() << " --- value: " << value.label;
|
qDebug() << " --- value: " << value.label;
|
||||||
_transmitter.enqueueValue( value );
|
|
||||||
|
// statt '_transmitter.enqueueValue( value )' entkoppeln
|
||||||
|
// wir das eleganter über emit valueCreated()
|
||||||
|
|
||||||
|
//_transmitter.enqueueValue( value );
|
||||||
|
emit valueCreated(value);
|
||||||
|
|
||||||
emit valueTouched( value.rowInModel );
|
emit valueTouched( value.rowInModel );
|
||||||
QApplication::processEvents();
|
|
||||||
|
processEventsFor(500);
|
||||||
|
//QApplication::processEvents();
|
||||||
// Thread schlafen lassen (Simulation einer blockierenden Operation)
|
// Thread schlafen lassen (Simulation einer blockierenden Operation)
|
||||||
QThread::msleep(500);
|
//QThread::msleep(500);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,9 +54,6 @@ public:
|
|||||||
|
|
||||||
BCValue makeValue(BCDevice::ID deviceID, const BCValueParams& params );
|
BCValue makeValue(BCDevice::ID deviceID, const BCValueParams& params );
|
||||||
|
|
||||||
// Public API für die Applikation
|
|
||||||
void transmitValue( const BCValue& value);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void loadBikeData();
|
void loadBikeData();
|
||||||
@@ -67,7 +64,7 @@ public slots:
|
|||||||
signals:
|
signals:
|
||||||
|
|
||||||
// Internes Signal, um Daten an den Worker Thread zu senden
|
// Internes Signal, um Daten an den Worker Thread zu senden
|
||||||
void newCommandArrived(const BCValue& cmd);
|
void valueCreated(const BCValue& cmd);
|
||||||
//void valuedTouched(const BCValue& cmd);
|
//void valuedTouched(const BCValue& cmd);
|
||||||
void valueTouched(int rowInModel );
|
void valueTouched(int rowInModel );
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user