- Auto-scroll standard aktiv
- Tag-Filter wird gespeichert - Tag Monitor kann bei einem Tag jetzt pro Key mehrere Werte in einer Tabelle anzeigen - Bug für Clear behoben
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
#include <QMetaObject>
|
||||
#include <QResizeEvent>
|
||||
|
||||
// Enumerate /dev/video* entries
|
||||
static QStringList enumerateVideoDevices()
|
||||
{
|
||||
QStringList devices;
|
||||
@@ -19,8 +18,6 @@ static QStringList enumerateVideoDevices()
|
||||
return devices;
|
||||
}
|
||||
|
||||
// ── ctor / dtor ───────────────────────────────────────────────────────────────
|
||||
|
||||
VideoWidget::VideoWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
@@ -32,20 +29,20 @@ VideoWidget::VideoWidget(QWidget *parent)
|
||||
|
||||
connect(m_thread, &QThread::finished, m_worker, &QObject::deleteLater);
|
||||
|
||||
connect(m_worker, &V4l2Worker::newFrame, this, &VideoWidget::onNewFrame,
|
||||
connect(m_worker, &V4l2Worker::newFrame, this, &VideoWidget::onNewFrame,
|
||||
Qt::QueuedConnection);
|
||||
connect(m_worker, &V4l2Worker::captureStarted, this, [this](const QString &dev, int w, int h, const QString &fmt) {
|
||||
connect(m_worker, &V4l2Worker::captureStarted, this, [this](const QString &dev, int w, int h, const QString &fmt) {
|
||||
m_infoLabel->setText(tr("%1 %2×%3 %4").arg(dev).arg(w).arg(h).arg(fmt));
|
||||
m_running = true;
|
||||
m_startBtn->setText(tr("■ Stop"));
|
||||
});
|
||||
connect(m_worker, &V4l2Worker::captureStopped, this, [this] {
|
||||
connect(m_worker, &V4l2Worker::captureStopped, this, [this] {
|
||||
m_running = false;
|
||||
m_startBtn->setText(tr("▶ Start"));
|
||||
m_infoLabel->setText(tr("Stopped"));
|
||||
update();
|
||||
});
|
||||
connect(m_worker, &V4l2Worker::errorOccurred, this, [this](const QString &msg) {
|
||||
connect(m_worker, &V4l2Worker::errorOccurred, this, [this](const QString &msg) {
|
||||
m_infoLabel->setText(tr("Error: %1").arg(msg));
|
||||
m_running = false;
|
||||
m_startBtn->setText(tr("▶ Start"));
|
||||
@@ -60,8 +57,6 @@ void VideoWidget::shutdown()
|
||||
return;
|
||||
m_shutdownDone = true;
|
||||
|
||||
// stopCapture() sets m_running=false and joins the std::thread internally.
|
||||
// Must happen before we quit the Qt event thread.
|
||||
m_worker->stopCapture();
|
||||
|
||||
if (m_thread && m_thread->isRunning()) {
|
||||
@@ -77,8 +72,6 @@ VideoWidget::~VideoWidget()
|
||||
shutdown();
|
||||
}
|
||||
|
||||
// ── UI setup ─────────────────────────────────────────────────────────────────
|
||||
|
||||
void VideoWidget::setupUi()
|
||||
{
|
||||
setMinimumHeight(140);
|
||||
@@ -87,7 +80,6 @@ void VideoWidget::setupUi()
|
||||
layout->setContentsMargins(2, 2, 2, 2);
|
||||
layout->setSpacing(3);
|
||||
|
||||
// ── Controls row ──────────────────────────────────────────────────────────
|
||||
auto *ctrlRow = new QHBoxLayout();
|
||||
ctrlRow->setSpacing(4);
|
||||
|
||||
@@ -97,7 +89,6 @@ void VideoWidget::setupUi()
|
||||
|
||||
auto *refreshBtn = new QPushButton("↻", this);
|
||||
refreshBtn->setMaximumWidth(26);
|
||||
refreshBtn->setToolTip(tr("Refresh device list"));
|
||||
connect(refreshBtn, &QPushButton::clicked, this, &VideoWidget::refreshDeviceList);
|
||||
|
||||
m_startBtn = new QPushButton(tr("▶ Start"), this);
|
||||
@@ -111,7 +102,6 @@ void VideoWidget::setupUi()
|
||||
|
||||
m_screenshotBtn = new QPushButton(tr("📷"), this);
|
||||
m_screenshotBtn->setMaximumWidth(32);
|
||||
m_screenshotBtn->setToolTip(tr("Save screenshot (PNG/JPG)"));
|
||||
connect(m_screenshotBtn, &QPushButton::clicked, this, &VideoWidget::onScreenshot);
|
||||
|
||||
ctrlRow->addWidget(m_deviceCombo, 1);
|
||||
@@ -121,24 +111,17 @@ void VideoWidget::setupUi()
|
||||
ctrlRow->addWidget(m_screenshotBtn);
|
||||
layout->addLayout(ctrlRow);
|
||||
|
||||
// ── Info label ────────────────────────────────────────────────────────────
|
||||
m_infoLabel = new QLabel(tr("No device started"), this);
|
||||
m_infoLabel->setStyleSheet("color: gray; font-size: 9px;");
|
||||
layout->addWidget(m_infoLabel);
|
||||
|
||||
// The video frame is drawn directly in paintEvent – no QLabel needed.
|
||||
// We leave stretch space for it.
|
||||
layout->addStretch(1);
|
||||
}
|
||||
|
||||
// ── Slots ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
void VideoWidget::onStartStop()
|
||||
{
|
||||
if (m_running)
|
||||
stopCapture();
|
||||
else
|
||||
startCapture();
|
||||
if (m_running) stopCapture();
|
||||
else startCapture();
|
||||
}
|
||||
|
||||
void VideoWidget::onFreeze(bool frozen)
|
||||
@@ -172,7 +155,14 @@ void VideoWidget::onNewFrame(const QImage &frame)
|
||||
return;
|
||||
m_frame = frame;
|
||||
updateScaled();
|
||||
update(); // trigger paintEvent
|
||||
update();
|
||||
}
|
||||
|
||||
void VideoWidget::clearFrame()
|
||||
{
|
||||
m_frame = QImage();
|
||||
m_scaled = QImage();
|
||||
update();
|
||||
}
|
||||
|
||||
void VideoWidget::refreshDeviceList()
|
||||
@@ -182,14 +172,11 @@ void VideoWidget::refreshDeviceList()
|
||||
const auto devices = enumerateVideoDevices();
|
||||
for (const auto &d : devices)
|
||||
m_deviceCombo->addItem(d);
|
||||
// Restore previous selection if still present
|
||||
const int idx = m_deviceCombo->findText(current);
|
||||
if (idx >= 0)
|
||||
m_deviceCombo->setCurrentIndex(idx);
|
||||
}
|
||||
|
||||
// ── Capture start/stop ────────────────────────────────────────────────────────
|
||||
|
||||
void VideoWidget::startCapture()
|
||||
{
|
||||
const QString dev = m_deviceCombo->currentText();
|
||||
@@ -197,7 +184,6 @@ void VideoWidget::startCapture()
|
||||
return;
|
||||
m_frame = QImage();
|
||||
m_scaled = QImage();
|
||||
// startCapture blocks in the worker thread until stopCapture() is called
|
||||
QMetaObject::invokeMethod(m_worker, "startCapture",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(QString, dev),
|
||||
@@ -210,11 +196,8 @@ void VideoWidget::stopCapture()
|
||||
QMetaObject::invokeMethod(m_worker, "stopCapture", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
// ── Paint ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
void VideoWidget::updateScaled()
|
||||
{
|
||||
// Video area = widget height minus the two control rows (~55 px)
|
||||
const QRect videoRect(0, 55, width(), height() - 55);
|
||||
if (videoRect.width() < 10 || videoRect.height() < 10 || m_frame.isNull())
|
||||
return;
|
||||
@@ -226,8 +209,6 @@ void VideoWidget::updateScaled()
|
||||
void VideoWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
|
||||
// Background
|
||||
p.fillRect(rect(), QColor(0x10, 0x10, 0x10));
|
||||
|
||||
if (m_scaled.isNull()) {
|
||||
@@ -237,14 +218,12 @@ void VideoWidget::paintEvent(QPaintEvent *)
|
||||
return;
|
||||
}
|
||||
|
||||
// Centre the scaled frame in the video area
|
||||
const QRect videoRect(0, 55, width(), height() - 55);
|
||||
const QPoint origin(
|
||||
videoRect.left() + (videoRect.width() - m_scaled.width()) / 2,
|
||||
videoRect.top() + (videoRect.height() - m_scaled.height()) / 2);
|
||||
p.drawImage(origin, m_scaled);
|
||||
|
||||
// Frozen overlay
|
||||
if (m_frozen) {
|
||||
p.setPen(QColor(0xff, 0xcc, 0x00));
|
||||
p.setFont(QFont("Sans", 9, QFont::Bold));
|
||||
|
||||
Reference in New Issue
Block a user