自定義QTimeEdit

會頭痛的可達鴨發表於2019-06-14

1、由於預設的QTimeEdit輸入有點反人類(輸入有點問題,全選不能輸入,故自定義了一個TimeEdit)

#ifndef HITIMEEDIT_H
#define HITIMEEDIT_H
#include <QFrame>
#include <QTime>
#include <QLineEdit>

class TimeEdit : public QFrame
{
    Q_OBJECT
public:
    TimeEdit(QWidget *parent = nullptr);
    ~TimeEdit();

public:

    QTime time();
    qreal msec();
    qreal sec();
    void setSec(qreal sec);
    void setMsec(int msec);

    void setTime(QTime time);
    void setTime(const QString& qsTime);
    //單位是毫秒
    void setTime(qreal nTime);
    void clearMaximumTime();
    void setMaximumTime(const QTime &time);
    void setReadOnly(bool bRead); 
    //是否展示毫秒
    void setDisplayMsec(bool bVisible);

signals:
    void timeChanged(const QTime &time);

protected:
    void wheelEvent(QWheelEvent *event) override;
    virtual void keyReleaseEvent(QKeyEvent *event);
    virtual bool eventFilter(QObject *obj, QEvent *event);

protected slots:
    void onEditChanged();

private:
    void InitUI();
    /*把帶符號的字串轉化為不帶符號的*/
    QString GetTimeString(const QString & qsTime);
    QTime QStringToTime(const QString & qsTim);
    void UpdateUi();
    void Update();

private:
    QTime           m_time;
    QTime           m_maxTime;
    QString         m_qsTime;
    QLineEdit      *m_pLineEdit;
    bool            m_bRead;
    bool            m_bVisibleMsec;
};

#endif

#include "TimeEdit.h"
#include <QRegExpValidator>
#include <QHBoxLayout>
#include <QKeyEvent>

TimeEdit::TimeEdit(QWidget *parent)
    : QFrame(parent)
    , m_bRead(true)
{
    InitUI();
}

TimeEdit::~TimeEdit()
{

}

QTime TimeEdit::time()
{
    return m_time;
}

qreal TimeEdit::msec()
{
    QTime time(0,0,0,0);
    return time.msecsTo(m_time);
}

qreal TimeEdit::sec()
{
    QTime time(0, 0, 0, 0);
    return time.msecsTo(m_time) / 1000.0;
}

void TimeEdit::setSec(qreal sec)
{
    setTime(1000 * sec);
}

void TimeEdit::setMsec(int msec)
{
    setTime(msec);
}

void TimeEdit::setTime(QTime time)
{
    if (time.toString("hh:mm:ss.zzz") == m_qsTime)
    {
        UpdateUi();
        return;
    }

    if (time > m_maxTime)
    {
        UpdateUi();
        return;
    }
    m_time = time;
    Update();
    emit timeChanged(m_time);
}

void TimeEdit::setTime(const QString& qsTime)
{
    QString qsText = GetTimeString(qsTime);
    if (qsText == GetTimeString(m_qsTime))
    {
        UpdateUi();
        return;
    }

    setTime(QStringToTime(qsText));
}

void TimeEdit::setTime(qreal nTime)
{
    if (nTime < 0 || nTime >= 86400000)
    {
        UpdateUi();
        return;
    }
    QTime time(0, 0, 0, 0);
    time.addMSecs(nTime);
    setTime(time);
}

void TimeEdit::clearMaximumTime()
{
    m_maxTime.setHMS(23, 59, 59, 999);
}

void TimeEdit::setMaximumTime(const QTime &time)
{
    m_maxTime = time;
}

void TimeEdit::setReadOnly(bool bRead)
{
    m_bRead = bRead;
    m_pLineEdit->setReadOnly(bRead);
}

void TimeEdit::setDisplayMsec(bool bVisible)
{
    m_bVisibleMsec = bVisible;
    if (m_bVisibleMsec)
    {
        m_pLineEdit->setInputMask("00:00:00.000;_");
    }
    else
    {
        m_pLineEdit->setInputMask("00:00:00;_");
    }
    Update();
}

void TimeEdit::wheelEvent(QWheelEvent *event)
{
    QWidget::wheelEvent(event);
}

void TimeEdit::keyReleaseEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)
    {
        onEditChanged();
        this->clearFocus();
    }
    QFrame::keyReleaseEvent(event);
}

bool TimeEdit::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::FocusOut)
    {
        onEditChanged();
    }
    return QObject::eventFilter(obj, event);
}

void TimeEdit::onEditChanged()
{
    if (m_bVisibleMsec)
    {
        setTime(m_pLineEdit->text());
    }
    else
    {
        setTime(m_pLineEdit->text()+ "000");
    }
}

void TimeEdit::InitUI()
{
    m_time.setHMS(0,0,0,0);
    m_qsTime = QString("00:00:00.000");

    m_pLineEdit = new QLineEdit(this);
    m_pLineEdit->setAcceptDrops(false);
    m_pLineEdit->setAttribute(Qt::WA_InputMethodEnabled, false);
    m_pLineEdit->setContextMenuPolicy(Qt::NoContextMenu);
    m_pLineEdit->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum, QSizePolicy::LineEdit));
    m_pLineEdit->setAttribute(Qt::WA_MacShowFocusRect);
    m_pLineEdit->setStyleSheet("border:none;");
    m_pLineEdit->setFocusPolicy(Qt::StrongFocus);
    m_pLineEdit->installEventFilter(this);
    connect(m_pLineEdit, &QLineEdit::editingFinished, this, &TimeEdit::onEditChanged);

    m_pLineEdit->setInputMask("00:00:00.000;_");
    QRegExpValidator *validator = nullptr;
    QRegExp rx("[0-9]+$");
    validator = new QRegExpValidator(rx, this);
    m_pLineEdit->setValidator(validator);

    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->addWidget(m_pLineEdit);
    layout->setSpacing(0);
    layout->setMargin(0);
    setLayout(layout);

    QSizePolicy policy = sizePolicy();
    setSizePolicy(QSizePolicy::Expanding, policy.verticalPolicy());
    this->setFocusProxy(m_pLineEdit);

    m_pLineEdit->setText(m_qsTime);
    m_maxTime.setHMS(23, 59, 59, 999);
}

QString TimeEdit::GetTimeString(const QString & qsTime)
{
    QString qsDstTime = qsTime;
    qsDstTime.replace("-", "");
    qsDstTime.replace(".", "");
    qsDstTime.replace(":", "");
    return qsDstTime;
}

QTime TimeEdit::QStringToTime(const QString & qsTime)
{
    QString qsDesTime = "000000000" + qsTime;
    qsDesTime = qsDesTime.right(9);
    
    int nHour = qsDesTime.mid(0, 2).toInt();
    int nMinute = qsDesTime.mid(2, 2).toInt();
    int nSecond = qsDesTime.mid(4, 2).toInt();
    int nMillisecond = qsDesTime.mid(6, 3).toInt();

    if (nHour >= 24 || nMinute >= 60 || nSecond >= 60)
    {
        return m_time;
    }
    QTime time(nHour, nMinute, nSecond, nMillisecond);
    return time;
}

void TimeEdit::UpdateUi()
{
    disconnect(m_pLineEdit, &QLineEdit::editingFinished, this, &TimeEdit::onEditChanged);
    m_pLineEdit->setText(m_qsTime);
    connect(m_pLineEdit, &QLineEdit::editingFinished, this, &TimeEdit::onEditChanged);
}

void TimeEdit::Update()
{
    if (m_bVisibleMsec)
    {
        m_qsTime = m_time.toString("hh:mm:ss.zzz");
    }
    else
    {
        m_qsTime = m_time.toString("hh:mm:ss");
    }
    m_pLineEdit->setText(m_qsTime);
}

備註:這裡沒有支援setDisplayFormat等功能,可以根據自己的需要去自定義