add QbreathingLight Class

This commit is contained in:
2025-08-22 10:59:38 +08:00
parent e3f9abfd97
commit 4bf7977a30
15 changed files with 219 additions and 8 deletions

View File

@@ -0,0 +1,86 @@
#include "QBreathingLight.h"
#include <QPainter>
#include <QColor>
#include <algorithm>
QBreathingLight::QBreathingLight(QWidget *parent)
: QWidget(parent)
, m_opacity(1.0f)
, m_isFlashing(false)
, m_flashColor(Qt::red)
, m_flashDuration(3000) // Ĭ<><C4AC><EFBFBD><EFBFBD>˸3<CBB8><33>
{
// <20><><EFBFBD>ù̶<C3B9><CCB6><EFBFBD>С
setFixedSize(40, 40);
// <20><><EFBFBD>Ӷ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>źŲ<C5BA>
connect(&m_animationTimer, &QTimer::timeout, this, &QBreathingLight::updateAnimation);
}
void QBreathingLight::setFlashDuration(int milliseconds)
{
m_flashDuration = milliseconds;
}
void QBreathingLight::setFlashColor(const QColor &color)
{
m_flashColor = color;
}
void QBreathingLight::triggerSignal()
{
if (!m_isFlashing) {
m_isFlashing = true;
m_flashStartTime = QTime::currentTime();
m_animationTimer.start(30); // 30ms<6D><73><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
}
}
void QBreathingLight::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// <20><><EFBFBD>Ʊ<EFBFBD><C6B1><EFBFBD>
painter.fillRect(rect(), QBrush(QColor(240, 240, 240)));
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>
QPoint center = rect().center();
int radius = qMin(width(), height()) / 3;
// <20><><EFBFBD><EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ
QColor color;
if (m_isFlashing) {
color = m_flashColor;
color.setAlphaF(m_opacity);
}
else {
color = Qt::green; // δ<><CEB4><EFBFBD><EFBFBD>״̬<D7B4><CCAC>ʾ<EFBFBD><CABE>ɫ
}
// <20><><EFBFBD>ƺ<EFBFBD><C6BA><EFBFBD><EFBFBD><EFBFBD>
painter.setBrush(QBrush(color));
painter.setPen(Qt::NoPen);
painter.drawEllipse(center, radius, radius);
}
void QBreathingLight::updateAnimation()
{
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ񳬹<C7B7><F1B3ACB9><EFBFBD>˸<EFBFBD><CBB8><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
int elapsed = m_flashStartTime.msecsTo(QTime::currentTime());
if (elapsed >= m_flashDuration) {
m_isFlashing = false;
m_opacity = 1.0f;
m_animationTimer.stop();
update();
return;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7> (ʹ<><CAB9><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><D2BA><EFBFBD>ʵ<EFBFBD><CAB5>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7>)
float progress = static_cast<float>(elapsed) / m_flashDuration;
m_opacity = 0.5f * (1.0f + sin(progress * 2 * 3.14 * 5)); // ÿ<><C3BF><EFBFBD><EFBFBD>˸2<CBB8><32>
update(); // <20><><EFBFBD><EFBFBD><EFBFBD>ػ<EFBFBD>
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include <QWidget>
#include <QTimer>
#include <QColor>
#include <QTime>
class QBreathingLight : public QWidget
{
Q_OBJECT
public:
explicit QBreathingLight(QWidget *parent = nullptr);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸<EFBFBD><CBB8><EFBFBD><EFBFBD>
void setFlashDuration(int milliseconds); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸<EFBFBD>ܳ<EFBFBD><DCB3><EFBFBD>ʱ<EFBFBD><CAB1>
void setFlashColor(const QColor &color); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸<EFBFBD><CBB8>ɫ
public slots:
void triggerSignal(); // <20><><EFBFBD><EFBFBD><EFBFBD>źţ<C5BA><C5A3><EFBFBD>ʼ<EFBFBD><CABC>˸
protected:
void paintEvent(QPaintEvent *event) override;
private slots:
void updateAnimation();
private:
float m_opacity; // <20><>ǰ͸<C7B0><CDB8><EFBFBD><EFBFBD>
bool m_isFlashing; // <20>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸
QTimer m_animationTimer; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
QColor m_flashColor; // <20><>˸<EFBFBD><CBB8>ɫ
QTime m_flashStartTime; // <20><>˸<EFBFBD><CBB8>ʼʱ<CABC><CAB1>
int m_flashDuration; // <20><>˸<EFBFBD><CBB8><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>(<28><><EFBFBD><EFBFBD>)
};

View File

@@ -79,6 +79,18 @@ QMainwindow::QMainwindow(QWidget *parent)
}, Qt::QueuedConnection // <20><><EFBFBD><EFBFBD>ʹ<EFBFBD>ÿ<EFBFBD><C3BF>߳<EFBFBD><DFB3><EFBFBD><EFBFBD><EFBFBD>
);
auto manager = QBigOrderManager::instance();
QObject::connect(
manager,
&QBigOrderManager::markBigOrderSignal,
this,
[this]() {
m_lightWidget->triggerSignal();
}, Qt::QueuedConnection // <20><><EFBFBD><EFBFBD>ʹ<EFBFBD>ÿ<EFBFBD><C3BF>߳<EFBFBD><DFB3><EFBFBD><EFBFBD><EFBFBD>
);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7>
if (!m_dataAcquisition || !m_dataAcquisition->m_InterfaceFutu) {
qCritical() << "Invalid data acquisition or interface";
@@ -255,6 +267,17 @@ void QMainwindow::initWidget()
// }
//});
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƿؼ<C6BF>
m_lightWidget = new QBreathingLight();
ui.layoutBreathing->addWidget(m_lightWidget, 0, Qt::AlignCenter);
//// <20><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>Զ<EFBFBD>ʱ<EFBFBD><CAB1>
//QTimer *autoTestTimer = new QTimer(this);
//connect(autoTestTimer, &QTimer::timeout, m_lightWidget, &QBreathingLight::triggerSignal);
//autoTestTimer->start(2000); // ÿ2<C3BF><32><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
//connect(ui.btnConnOpend, &QPushButton::clicked, m_lightWidget, &QBreathingLight::triggerSignal);
}
void QMainwindow::initReplyManage()

View File

@@ -11,6 +11,7 @@
#include "ui_QMainwindow.h"
#include "QDataAcquisition.h"
#include "QBreathingLight.h"
#include "..\Sqbase\qlogmanager.h"
#include "..\Sqbase\qlogviewer.h"
@@ -34,6 +35,8 @@ private:
QDataAcquisition* m_dataAcquisition;
QTimer* m_netCheckTimer;
QBreathingLight *m_lightWidget;
public:
void initWidget();

View File

@@ -42,6 +42,40 @@
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QWidget" name="widget_6" native="true">
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="layoutBreathing">
<property name="spacing">
<number>0</number>
</property>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_3" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_7">

View File

@@ -111,6 +111,7 @@
<ClCompile Include="..\Sqbase\qlogmanager.cpp" />
<ClCompile Include="..\Sqbase\qlogviewer.cpp" />
<ClCompile Include="..\Sqbase\qorderprocessor.cpp" />
<ClCompile Include="QBreathingLight.cpp" />
<ClCompile Include="QDataAcquisition.cpp" />
<ClCompile Include="QMainwindow.cpp" />
<ClCompile Include="main.cpp" />
@@ -127,6 +128,7 @@
<QtMoc Include="..\Sqbase\ordertypedelegate.h" />
<ClInclude Include="..\Sqbase\OrderBookParser.h" />
<ClInclude Include="BZStruct.h" />
<QtMoc Include="QBreathingLight.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="resource1.h" />
<ClInclude Include="x64\Debug\uic\ui_QMainwindow.h" />

View File

@@ -76,6 +76,9 @@
<ClCompile Include="..\Sqbase\OrderBookParser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="QBreathingLight.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="x64\Debug\uic\ui_QMainwindow.h">
@@ -122,6 +125,9 @@
<QtMoc Include="..\Sqbase\qorderprocessor.h">
<Filter>Header Files</Filter>
</QtMoc>
<QtMoc Include="QBreathingLight.h">
<Filter>Header Files</Filter>
</QtMoc>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Resource.rc">

Binary file not shown.

Binary file not shown.

View File

@@ -72,6 +72,8 @@ bool QBigOrderManager::addBigOrder(const BigOrderInfo &order)
locker.unlock(); // <20>Ƚ<EFBFBD><C8BD><EFBFBD><EFBFBD>ٷ<EFBFBD><D9B7>ź<EFBFBD>
emit bigOrderAdded(order);
emit markBigOrderSignal();
return true;
}

View File

@@ -38,6 +38,8 @@ signals:
//void bigOrdersUpdated();
void saveOverRefreshView();
void markBigOrderSignal();
protected:
explicit QBigOrderManager(QObject *parent = nullptr);
~QBigOrderManager();

View File

@@ -197,7 +197,13 @@ void QBigOrderViewer::updateView()
rowItems << new QStandardItem(QString::number(std::fabs(order->volume/1000)) + "K");
rowItems << new QStandardItem(QString::number(order->price, 'f', 2));
rowItems << new QStandardItem(QString::number(order->level));
rowItems << new QStandardItem(order->svrRecvTime.mid(12));
QString str = order->svrRecvTime.mid(11);
if (str == nullptr)
{
QDateTime dateTime = QDateTime::currentDateTime();
str = dateTime.toString("hh:mm:ss");
}
rowItems << new QStandardItem(str);
m_model->appendRow(rowItems);
}
}
@@ -247,7 +253,13 @@ void QBigOrderViewer::setRowData(int row, QSharedPointer<BigOrderInfo> order)
QString::number(order->price, 'f', 2));
m_model->setData(m_model->index(row, 5),
QString::number(order->level));
m_model->setData(m_model->index(row, 6), order->svrRecvTime);
QString str = order->svrRecvTime.mid(11);
if (str == nullptr)
{
QDateTime dateTime = QDateTime::currentDateTime();
str = dateTime.toString("hh:mm:ss");
}
m_model->setData(m_model->index(row, 6), str);
}
bool QBigOrderViewer::matchesFilter(QSharedPointer<BigOrderInfo> order)

View File

@@ -6,6 +6,7 @@
#include <QFileDialog>
#include <QTextStream>
#include <QCoreApplication>
#include <QDateTime>
#include <QDebug>
@@ -121,7 +122,13 @@ void QHistoryOrderDialog::loadOrdersForDate(const QDate &date)
rowItems << new QStandardItem(QString::number(std::fabs(order->volume / 1000)) + "K");
rowItems << new QStandardItem(QString::number(order->price, 'f', 2));
rowItems << new QStandardItem(QString::number(order->level));
rowItems << new QStandardItem(order->svrRecvTime.mid(12));
QString str = order->svrRecvTime.mid(11);
if (str == nullptr)
{
QDateTime dateTime = QDateTime::currentDateTime();
str = dateTime.toString("hh:mm:ss");
}
rowItems << new QStandardItem(str);
m_model->appendRow(rowItems);
}

View File

@@ -92,10 +92,9 @@ QVector<BigOrderInfo> QOrderProcessor::findMaxVolumeItem(const OrderBookData & d
for (int i = 0; i < items.size(); i++) {
// 同一个价格挡位的订单中股票数量大于,阈值才有可能是大单
if (volume < items[i].volume) {
for (int j = 0; j< items[i].orderCount; j++)
for (int j = 0; j< items[i].details.size(); j++) // 超过list的最大数量就不会返回数据了
{
try {
if (items[i].details.size() == 0) continue;
if (volume < items[i].details[j].volume)
{
findBigOrder = true;
@@ -124,10 +123,9 @@ QVector<BigOrderInfo> QOrderProcessor::findMaxVolumeItem(const OrderBookData & d
for (int i = 0; i < items.size(); i++) {
// 同一个价格挡位的订单中股票数量大于,阈值才有可能是大单
if (volume < items[i].volume) {
for (int j = 0; j< items[i].orderCount; j++)
for (int j = 0; j< items[i].details.size(); j++)
{
try {
if (items[i].details.size() == 0) continue;
if (volume < items[i].details[j].volume)
{
findBigOrder = true;

View File

@@ -1,8 +1,9 @@
<EFBFBD><EFBFBD>Ʊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
09885,200000
00581,700000
00581,300000
03383,800000
02666,500000
00839,500000
06098,600000
06865,150000
00700,10000
1 股票代码 检测阈值
2 09885 200000
3 00581 700000 300000
4 03383 800000
5 02666 500000
6 00839 500000
7 06098 600000
8 06865 150000
9 00700 10000