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 后查看