QML完全模仿飞书日程界面(三)周的部分

发布于:2022-12-28 ⋅ 阅读:(698) ⋅ 点赞:(0)

QML完全模仿飞书日程界面(三)周的部分

第一期链接: QML 完全模拟飞书日程界面(一).
上一期链接: QML 完全模拟飞书日程界面(二).以及最后实现的效果:
日程标题


日程



前言

分为几个部分,和日一样有:背景的线条,左侧的一天24小时的刻度,红色的线条表示当前的时间,以及最后的可适应滚轮的上下滚动以及窗口的放大缩小,同时区别是:将每一行分为了7列,表头有每一天是当月的第几号和当周的第几天。


一、背景部分

还是按照qml给提供的方法自绘控件,继承自QQuickPaintedItem,重载paint函数,实现绘制一个横竖的方格或者只有横线的线条背景,线条能够跟随窗口变化而变化,为了实现线条能够随窗口改变而改变,每次窗口大小的改变都会调用paint函数,在paint函数里我们每次都会调用createRowLines(), createColumnLines()这两个方法,这两个方法会根据当前窗口重新计算新的线条的长度,这样就完成了线条随背景变化而变化,废话不多说,上代码
代码如下:

  • datetable.h
#ifndef DATETABLE_H
#define DATETABLE_H
#include <QtQuick/QQuickPaintedItem>
#include <QColor>
#include <QStringList>
#include <QLine>
#include <QJsonArray>
#include <QTimer>

class DateTable : public QQuickPaintedItem
{
    Q_OBJECT

public:
    explicit DateTable(QQuickItem *parent = nullptr);
	//行高,行数,列宽,列数
    Q_PROPERTY(qreal rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged)
    Q_PROPERTY(qreal rowH READ rowH WRITE setRowH NOTIFY rowHChanged)
    Q_PROPERTY(qreal columnCount READ columnCount WRITE setColumnCount NOTIFY columnCountChanged)
    Q_PROPERTY(qreal columnW READ columnW WRITE setColumnW NOTIFY columnWChanged)
    //列头和行头的文本
    Q_PROPERTY(QJsonArray rowHeadNames READ rowHeadNames WRITE setRowHeadNames NOTIFY rowHeadNamesChanged)
    Q_PROPERTY(QJsonArray columnHeadNames READ columnHeadNames WRITE setColumnHeadNames NOTIFY columnHeadNamesChanged)
    //1,有行有列,2,只有行没有列,3,只有列没有行
    Q_PROPERTY(int tableType READ tableType WRITE setTableType NOTIFY tableTypeChanged) 
    //行头的宽高,字体大小
    Q_PROPERTY(qreal rowHeadW READ rowHeadW WRITE setRowHeadW NOTIFY rowHeadWChanged)
    Q_PROPERTY(qreal rowHeadH READ rowHeadH WRITE setRowHeadH NOTIFY rowHeadHChanged)
    Q_PROPERTY(int rowHeadfontSize READ rowHeadfontSize WRITE setRowHeadfontSize NOTIFY rowHeadfontSizeChanged)
	// 今天
	Q_PROPERTY(int curDay READ curDay WRITE setCurDay NOTIFY curDayChanged)

    // 重载QQuickPaintedItem的paint函数,实现自定义绘图
    void paint(QPainter *painter);

    qreal rowCount() const;
    void setRowCount(qreal newRowCount);

    qreal rowH() const;
    void setRowH(qreal newRowH);

    qreal columnCount() const;
    void setColumnCount(qreal newColumnCount);

    qreal columnW() const;
    void setColumnW(qreal newColumnW);

    int tableType() const;
    void setTableType(int newTableType);

    const QJsonArray &rowHeadNames() const;
    void setRowHeadNames(const QJsonArray &newRowHeadNames);

    const QJsonArray &columnHeadNames() const;
    void setColumnHeadNames(const QJsonArray &newColumnHeadNames);

    qreal rowHeadW() const;
    void setRowHeadW(qreal newRowHeadW);

    qreal rowHeadH() const;
    void setRowHeadH(qreal newRowHeadH);

    int rowHeadfontSize() const;
    void setRowHeadfontSize(int newRowHeadfontSize);

    virtual void mouseDoubleClickEvent(QMouseEvent *ev);

    int curDay() const;
    void setCurDay(int newCurDay);


private:
	//创建行和列的线条数据
    void createRowLines();
    void createColumnLines();
	//绘制文本和线条
    void drawText(QPainter *painter);
    void drawLines(QPainter *painter);

signals:
    void rowCountChanged();
    void rowHChanged();
    void columnCountChanged();
    void columnWChanged();
    void rowHeadNamesChanged();
    void columnHeadNamesChanged();
    void tableTypeChanged();
    void rowHeadWChanged();
    void rowHeadHChanged();
    void rowHeadfontSizeChanged();
    void curDayChanged();

private:
    qreal m_rowCount = 0;
    qreal m_rowH = 50;
    qreal m_columnCount = 0;
    qreal m_columnW = 0;
    QJsonArray m_rowHeadNames;
    QJsonArray m_columnHeadNames;
    qreal m_rowHeadW = 30;
    qreal m_rowHeadH = 20;
    int m_tableType = 1;//0 只有行,1只有列,2有行有列
    QVector<QLine> m_rowLines;//行的横线
    QVector<QLine> m_columnLines;//列的竖线
    int m_rowHeadfontSize = 12;
    QTimer *m_timer;
    int m_curDay = -1;
};
#endif // DATETABLE_H

  • datetable.cpp
#include "datetable.h"
#include <QPainter>
#include <QDebug>
#include <QRect>


DateTable::DateTable(QQuickItem *parent): QQuickPaintedItem(parent)
{
    setAcceptedMouseButtons(Qt::AllButtons);
}

void DateTable::paint(QPainter *painter)
{
    drawLines(painter);
    drawText(painter);
}

qreal DateTable::rowCount() const
{
    return m_rowCount;
}

void DateTable::setRowCount(qreal newRowCount)
{
    if (qFuzzyCompare(m_rowCount, newRowCount))
        return;
    m_rowCount = newRowCount;
    emit rowCountChanged();
}

qreal DateTable::rowH() const
{
    return m_rowH;
}

void DateTable::setRowH(qreal newRowH)
{
    if (qFuzzyCompare(m_rowH, newRowH))
        return;
    m_rowH = newRowH;
    emit rowHChanged();
}

qreal DateTable::columnCount() const
{
    return m_columnCount;
}

void DateTable::setColumnCount(qreal newColumnCount)
{
    if (qFuzzyCompare(m_columnCount, newColumnCount))
        return;
    m_columnCount = newColumnCount;
    emit columnCountChanged();
}

qreal DateTable::columnW() const
{
    return m_columnW;
}

void DateTable::setColumnW(qreal newColumnW)
{
    if (qFuzzyCompare(m_columnW, newColumnW))
        return;
    m_columnW = newColumnW;
    emit columnWChanged();
}

int DateTable::tableType() const
{
    return m_tableType;
}

void DateTable::setTableType(int newTableType)
{
    if (m_tableType == newTableType)
        return;
    m_tableType = newTableType;
    emit tableTypeChanged();
}

void DateTable::createRowLines()
{
    qreal rcount = rowCount();
    qreal rheight = rowH();
    if(!m_rowLines.isEmpty()){
        m_rowLines.clear();
    }
    int rectW = rowHeadW();

    for (int i = 0 ;i <= rcount; i++) {
        m_rowLines<<QLine(10 + rectW, 10 + rheight * i, width() - 20, 10 + rheight * i);
    }
}

void DateTable::createColumnLines()
{
    qreal colcount = columnCount();
    qreal colwidth = columnW();
    qreal rcount = rowCount();
    qreal rheight = rowH();

    if(!m_columnLines.isEmpty()){
        m_columnLines.clear();
    }
    int rectW = rowHeadW();
    for (int i = 0 ;i <= colcount; i++) {
        m_columnLines<<QLine(10 + rectW + colwidth * i, 10 , 10 + rectW + colwidth * i,rcount * rheight + 10);
    }
}

void DateTable::drawText(QPainter *painter)
{
    painter->save();
    painter->setPen(QColor("#7E8594"));
    painter->setBrush(Qt::white);
    painter->setRenderHint(QPainter::TextAntialiasing);//QPainter::Antialiasing消除图元边缘锯齿、QPainter::TextAntialiasing 消除文本边缘锯齿

    QFont font = painter->font();
    font.setPixelSize(rowHeadfontSize());
    painter->setFont(font);

    qreal rheight = rowH();

    int rectW = rowHeadW();
    int rectH = rowHeadH();
	//这里只写了左侧的文本,其他部分后续根据需要添加
    for (int i = 0; i < m_rowHeadNames.size(); i++) {
        const QRect rectangle = QRect(5,0 + i*rheight,rectW,rectH);;
        painter->drawText(rectangle, Qt::AlignCenter, m_rowHeadNames[i].toString());
    }
    painter->restore();
}

void DateTable::drawLines(QPainter *painter)
{
    createRowLines();
    createColumnLines();
    painter->save();
    painter->setPen(QColor(208,208,208));
    painter->setBrush(Qt::white);
    painter->setRenderHint(QPainter::Antialiasing);//QPainter::Antialiasing消除图元边缘锯齿、QPainter::TextAntialiasing 消除文本边缘锯齿
    painter->drawLines(m_rowLines);
    painter->drawLines(m_columnLines);
    painter->restore();
}

const QJsonArray &DateTable::rowHeadNames() const
{
    return m_rowHeadNames;
}

void DateTable::setRowHeadNames(const QJsonArray &newRowHeadNames)
{
    if (m_rowHeadNames == newRowHeadNames)
        return;
    m_rowHeadNames = newRowHeadNames;
    emit rowHeadNamesChanged();
}

const QJsonArray &DateTable::columnHeadNames() const
{
    return m_columnHeadNames;
}

void DateTable::setColumnHeadNames(const QJsonArray &newColumnHeadNames)
{
    if (m_columnHeadNames == newColumnHeadNames)
        return;
    m_columnHeadNames = newColumnHeadNames;
    emit columnHeadNamesChanged();
}

qreal DateTable::rowHeadW() const
{
    return m_rowHeadW;
}

void DateTable::setRowHeadW(qreal newRowHeadW)
{
    if (m_rowHeadW == newRowHeadW)
        return;
    m_rowHeadW = newRowHeadW;
    emit rowHeadWChanged();
}

qreal DateTable::rowHeadH() const
{
    return m_rowHeadH;
}

void DateTable::setRowHeadH(qreal newRowHeadH)
{
    if (m_rowHeadH == newRowHeadH)
        return;
    m_rowHeadH = newRowHeadH;
    emit rowHeadHChanged();
}

int DateTable::rowHeadfontSize() const
{
    return m_rowHeadfontSize;
}

void DateTable::setRowHeadfontSize(int newRowHeadfontSize)
{
    if (m_rowHeadfontSize == newRowHeadfontSize)
        return;
    m_rowHeadfontSize = newRowHeadfontSize;
    emit rowHeadfontSizeChanged();
}

void DateTable::mouseDoubleClickEvent(QMouseEvent *ev)
{
    qDebug()<<"DateTable ==ColorBlackLayer mouseDoubleClickEvent===";
    QQuickPaintedItem::mouseDoubleClickEvent(ev);
}
int DateTable::curDay() const
{
    return m_curDay;
}

void DateTable::setCurDay(int newCurDay)
{
    if (m_curDay == newCurDay)
        return;
    m_curDay = newCurDay;
    emit curDayChanged();
}


二、能够随时间和日期变化而变化的红色线条

还是按照qml给提供的方法自绘控件,继承自QQuickPaintedItem,重载paint函数,实现一个能够随时间变化而变化的线条,同时够跟随窗口变化而变化,这里要注意的是curDay 这个变量,是利用父类设置的curday,来计算出这个红色的线条所处的位置。

当前时间

代码如下:

  • currenttimeline.h
#ifndef CURRENTTIMELINE_H
#define CURRENTTIMELINE_H
#include <QtQuick/QQuickPaintedItem>
#include <QPainter>
#include <QTimer>
#include "datetable.h"

class CurrentTimeLine : public QQuickPaintedItem
{
    Q_OBJECT
public:
	//距离上方的高度占比
    Q_PROPERTY(float percentage READ percentage WRITE setPercentage NOTIFY percentageChanged)
    //这里注意,一定要给它设置父类为上面的datetable,不能单独使用
    explicit CurrentTimeLine(QQuickItem *parent );
    // 重载QQuickPaintedItem的paint函数,实现自定义绘图
    void paint(QPainter *painter);
    float percentage() const;
    //获取当前时间,并且根据当前时间计算占比,这个函数命名不好,写的不好,后续需要修改
    void getCurrentTime();
    void setPercentage(float newPercentage);
    virtual void mouseDoubleClickEvent(QMouseEvent *ev);
signals:
    void percentageChanged();
private:
	//绘制线条,文本,和左侧的小圆点
    void drawCurrentTimeLines(QPainter *painter);
    void drawText(QPainter *painter);
    void drawPoint(QPainter *painter);
private:
    QTimer *m_timer;
    float m_percentage = 0.0;
    QString m_currentTimeStr;
};

#endif // CURRENTTIMELINE_H

  • currenttimeline.cpp
#include "currenttimeline.h"
#include <QTime>
#include <QDebug>
#include <QString>
#include "datetable.h"

CurrentTimeLine::CurrentTimeLine(QQuickItem *parent): QQuickPaintedItem(parent)
{
    m_timer = new QTimer(this);
    connect(m_timer,SIGNAL(timeout()),this,SLOT(update()));//定时调用绘制事件函数
    m_timer->start(1000 * 60);//开启定时器,执行周期为1秒针

    qDebug()<<"====CurrentTimeLine===";
        setAcceptedMouseButtons(Qt::AllButtons);
}

void CurrentTimeLine::paint(QPainter *painter)
{
    drawCurrentTimeLines(painter);
    drawText(painter);
    drawPoint(painter);
}

void CurrentTimeLine::drawCurrentTimeLines(QPainter *painter)
{
    DateTable* mparent = qobject_cast<DateTable*>(this->parent());
    if(mparent){
        qDebug()<<"====drawCurrentTimeLines===";
        painter->save();
        getCurrentTime();
        painter->setPen(QColor("#E34451"));
        painter->setBrush(Qt::white);
        painter->setRenderHint(QPainter::Antialiasing);//QPainter::Antialiasing消除图元边缘锯齿、QPainter::TextAntialiasing 消除文本边缘锯齿
        float parentH = mparent->height();
        qreal parentColumnW = mparent->columnW();
        int curDay = mparent->curDay();
        int rectW = mparent->rowHeadW();
        int mH =  parentH * percentage();
        int parentW = mparent->width();
        qDebug()<<"curDay"<<curDay;
        if(parentColumnW && curDay != -1){
            painter->drawLine(10 + rectW + parentColumnW * curDay , mH ,10 + rectW + parentColumnW * (1 + curDay) , mH);
        }else{
            painter->drawLine(10 + rectW , mH , parentW-20 , mH);
        }

        painter->restore();
    }

}

void CurrentTimeLine::drawText(QPainter *painter)
{
    DateTable* mparent = qobject_cast<DateTable*>(this->parent());
    if(mparent){
        qDebug()<<"====drawText===";
        painter->save();

        painter->setBrush(Qt::white);
        painter->setRenderHint(QPainter::TextAntialiasing);//QPainter::Antialiasing消除图元边缘锯齿、QPainter::TextAntialiasing 消除文本边缘锯齿

        QFont font = painter->font();
        font.setPixelSize(mparent->rowHeadfontSize());
        painter->setFont(font);
        float parentH = mparent->height();
        int mH =  parentH * percentage();
        int rectW = mparent->rowHeadW();
        int rectH = mparent->rowHeadH();
        const QRect rectangle = QRect(5,mH - rectH/2,rectW,rectH);
        painter->setPen(Qt::white);
        painter->drawRect(rectangle);
        painter->setPen(QColor("#E34451"));
        painter->drawText(rectangle, Qt::AlignCenter, m_currentTimeStr);
        painter->restore();
    }
}

void CurrentTimeLine::drawPoint(QPainter *painter)
{
    DateTable* mparent = qobject_cast<DateTable*>(this->parent());
    if(mparent){
        qDebug()<<"====drawPoint===";
        painter->save();
        painter->setPen(QColor("#E34451"));
        painter->setBrush(QColor("#E34451"));
        painter->setRenderHint(QPainter::Antialiasing);//QPainter::Antialiasing消除图元边缘锯齿、QPainter::TextAntialiasing 消除文本边缘锯齿
        qreal parentColumnW = mparent->columnW();
        int curDay = mparent->curDay();
        float parentH = mparent->height();
        int mH =  parentH * percentage();
        int rectW = mparent->rowHeadW();
        if(parentColumnW && curDay != -1){
            painter->drawEllipse(10 + rectW - 3 + parentColumnW * curDay ,mH - 3,6,6);
        }else{
            painter->drawEllipse(10 + rectW - 3 ,mH - 3,6,6);
        }
        painter->restore();
    }
}


float CurrentTimeLine::percentage() const
{
    return m_percentage;
}

void CurrentTimeLine::getCurrentTime()
{
    QTime current_time = QTime::currentTime();
    float hour = current_time.hour();//当前的小时
    float minute = current_time.minute();//当前的分
    //    int second = current_time.second();//当前的秒
    //    int msec = current_time.msec();//当前的毫秒
    QString minuteStr;
    if(minute < 10){
        minuteStr = "0"+ QString::number(minute);
    }else{
        minuteStr = QString::number(minute);
    }
    m_currentTimeStr = QString::number(hour) + ":"+ minuteStr;
    float percentage = (hour * 60 + minute) / (24 * 60);
    setPercentage(percentage);
}

void CurrentTimeLine::setPercentage(float newPercentage)
{
    if (qFuzzyCompare(m_percentage, newPercentage))
        return;
    m_percentage = newPercentage;
    emit percentageChanged();
}

void CurrentTimeLine::mouseDoubleClickEvent(QMouseEvent *ev)
{
    qDebug()<<"==CurrentTimeLine mouseDoubleClickEvent===";
}


三、注册代码到qml

代码如下:
main函数中添加这两行

    qmlRegisterType<DateTable>("MControls", 1, 0, "DateTable");
    qmlRegisterType<CurrentTimeLine>("MControls", 1, 0, "CurrentTimeLine");

四、使界面能够随滚轮上下滚动,且当月第几周,第几天

这里上面的当月多少号,和当周第几天主要是利用了qml的DayOfWeekRow控件,然后自己去管理日期。

代码如下:

Item {
    id:_root
    property int day: 0
    property int date: 0

    property var days:[]
    DayOfWeekRow {
        id:_title
        locale: Qt.locale("zh_CN")

        anchors{
            top: parent.top
            left: parent.left
            leftMargin: 40
            right: parent.right
        }
        delegate: Item {
            Layout.fillWidth: true
            Layout.fillHeight: true
            Text {
                id: _week
                anchors{
                    left: parent.left
                    leftMargin: 12
                }
                font.family:  "PingFang SC"
                font.pixelSize: 12
                lineHeightMode: Text.FixedHeight
                lineHeight: 17
                font.bold: false
                text: model.shortName
                color: _root.day === model.day ? "#1962FF" : "#7E8594"
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
            }
            Text {
                anchors{
                    top: _week.bottom
                    left: parent.left
                    leftMargin: 12
                }
                font.family:  "DIN Alternate"
                font.pixelSize: 24
                lineHeightMode: Text.FixedHeight
                lineHeight: 28
                font.bold: false
                text: _root.days[model.day] ? _root.days[model.day] : ""
                color: _root.day === model.day ? "#1962FF" : "#7E8594"
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
            }
        }
        height: 40
    }
    Flickable {
        anchors{
            top: _title.bottom
            topMargin: 9
            left: parent.left
            right: parent.right
            bottom: parent.bottom
        }
        contentWidth: parent.width
        contentHeight: _dateTable2.height
        clip: true
        DateTable {
            id: _dateTable2
            width: parent.width
            height: 24 * 50 + 20
            rowCount: 24
            rowH: 50
            rowHeadfontSize:14
            rowHeadH: 20
            rowHeadW: 40
            columnCount: 7
            columnW: Math.ceil((parent.width-40)/7)
            curDay: _root.day
            rowHeadNames: ["00:00","01:00","02:00","03:00","04:00","05:00","06:00","07:00","08:00","09:00","10:00","11:00","12:00","13:00","14:00","15:00","16:00","17:00","18:00","19:00","20:00","21:00","22:00","23:00","24:00"]
            CurrentTimeLine{
                parent: _dateTable2
                width: parent.width
                height: parent.height
            }
        }
    }
}



总结

周所显示的效果(因为没有适配windows,还得用windows的开发环境,所以暂且是这样看着有点别扭)
一天时间线的效果
这一期暂且就到这里,如果有疑问可以留言。
预告:下一期要模仿部分
日程-月

—————————本文严禁转载—————————

本文含有隐藏内容,请 开通VIP 后查看