QML完全模仿飞书日程界面(二)日(一天)的部分

QML完全模仿飞书日程界面(二)日(一天)的部分

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


然后再贴一个本期要模仿的部分:

单天的日期显示



前言

分为几个部分,背景的线条,左侧的一天24小时的刻度,红色的线条表示当前的时间,以及最后的可适应滚轮的上下滚动以及窗口的放大缩小。


一、背景部分

还是按照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)

    // 重载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);

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();

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;
};
#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);
}

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

还是按照qml给提供的方法自绘控件,继承自QQuickPaintedItem,重载paint函数,实现一个能够随时间变化而变化的线条,同时够跟随窗口变化而变化。
红色线条
代码如下:

  • 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秒针
    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){
        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();
        if(parentColumnW){
            painter->drawLine(10 + rectW , mH , parentW-20 , mH);
        }
        painter->restore();
    }

}

void CurrentTimeLine::drawText(QPainter *painter)
{
    DateTable* mparent = qobject_cast<DateTable*>(this->parent());
    if(mparent){
        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){
        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){
            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");

四、使界面能够随滚轮上下滚动

代码如下:

import QtQuick 2.12
import QtQuick.Window 2.12
import Qt.labs.calendar 1.0
import QtLocation 5.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import MControls 1.0
import QtGraphicalEffects 1.0
//用flickable来实现使应鼠标滚轮滚动
Flickable {
    contentWidth: parent.width
    contentHeight: _dateTable.height
    clip: true
    DateTable {
        id: _dateTable
        width: parent.width
        height: 24 * 50 + 20
        rowCount: 24
        rowH: 50
        rowHeadfontSize:14
        rowHeadH: 20
        rowHeadW: 40
        // 这里只是表示展示的文本,也可以替换成随意一个文本
        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: _dateTable
            width: parent.width
            height: parent.height
        }
    }
}


总结

哈哈,果然还是MAC上面的显示效果更好一点,暂且切换回windows开发,所以截一个windows平台的效果:
一天时间线的效果
这一期暂且就到这里,如果有疑问可以留言。
预告:下一期要模仿他的周的部分(ps: hhh,windows就是丑,也和没有做windows适配有关系,真的是丑爆了,有时间把样式再做一下windows适配)
周

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值