hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

自定义日历(四)-区间挑选控件

2019-11-18杂谈搜奇网41°c
A+ A-

目次

  • 一、概述
  • 二、结果展现
  • 三、团体组织
  • 四、剖析完成
    • 1、QPickDate
    • 2、QDatePanel
    • 3、QDateWidget、QDateContent
    • 4、 调理绘制
  • 五、相干文章

原文链接:自定义日历(四)-区间挑选控件

一、概述

很早很早以前,写过几篇关于日历的文章,差别于Qt原生的控件,这些控件都是博主运用自绘的体式格局举行完成,因而可定制性更强一些,感兴趣的能够参考自定义日历(一)、自定义日历(二)和自定义日历(三))。

本篇文章照样继承来写我们的日历控件,依然采纳自绘的体式格局,带来越发炫酷的结果。看本文的题目就应该就可以邃晓,此次完成的是一个能够区间挑选的日历控件。

二、结果展现

结果图以下,一个简朴的结果展现。

日历控件与Qt原生的QDateEdit一样,是由一个按钮举行触发,弹出准期挑选面板。差别的是这个日历挑选面板由2个小的日期面板构成,离别是最先和完毕日期,划定规矩以下:

  1. 最先日期必需小于完毕日期
  2. 顶部有疾速返回按钮
  3. 选中的日期段上有高亮背景色
  4. 选中的日期点上有蓝色圆形标识
  5. 点击肯定按钮今后日期挑选面板封闭

三、团体组织

最先解说详细内容之前,先来看下团体的组织离别,完成这个日期段挑选控件,统共须要以下4个类,下图是工程组织

以下是4个类的申明

  1. QDateContent:单个日历窗口
  2. QDateWidget:包含了年月挑选的单个日历窗口
  3. QDatePanel:日期段挑选面板
  4. QPickDate:日期挑选按钮,用于呼出日期挑选面板

个中QPickDate类就是对外运用的类,运用也很简朴,能够像下面如许

QPickDate * pickDate = new QPickDate;
pickDate->SetQuickValue(QDatePanel::DAY_ONE);

意义是组织一个日期段挑选空间,然后初始时为挑选当天。有了一个大抵的相识后,下面最先细致的解说每一个类的完成历程

四、剖析完成

1、QPickDate

QPickDate类是对外导出类,也是我们运用的时刻须要相识的类,他的头文件完成以下

class QPickDate : public QPushButton
{
    Q_OBJECT

public:
    QPickDate(QWidget * parent = nullptr);
    ~QPickDate();

signals:
    void PickSuccess();//挑选日期胜利时挪用

public:
    void SetQuickValue(QDatePanel::QuickPick pick);
    void GetStartDate(unsigned short year, unsigned short month, unsigned short day);
    void GetEndDate(unsigned short year, unsigned short month, unsigned short day);

private slots:
    void OnClicked();

private:
    void InitializeUI();

private:
    QDatePanel::QuickPick m_ePick = QDatePanel::DAY_CUSTOM;
    QDatePanel * m_pPanel = nullptr;
};

接口看起来也比较简朴,SetQuickValue接口上一小节运用过,主如果用来初始化日期控件状况。GetStartDate和GetEndDate接口主要就是猎取日期段的最先时候和完毕时候。个中的完成详细的日期数据是从成员变量QDatePanel中猎取。

2、QDatePanel

以下是QDatePanel的头文件声明,因为代码量的题目,个中精简了一部份,QDatePanel这个类就是日期挑选面板,垂直方向由三部份构成,离别是疾速挑选日期挑选操纵按钮

class QDatePanel : public QFrame
{
    ...
public:
    enum QuickPick
    {
        DAY_ONE,//本日
        DAY_WEEK,//近一周
        DAY_MONTH,//近一月
        DAY_YEAR,//近一年
        DAY_CUSTOM,//自定义
    };

signals:
    void PickSuccess(QuickPick, const QString &);
    ...
public:
    QString GetQuickName(QuickPick pick);
    void SetQuickValue(QuickPick pick);
    void GetStartDate(unsigned short year, unsigned short month, unsigned short day);
    void GetEndDate(unsigned short year, unsigned short month, unsigned short day);

private:
    ...
};

疾速挑选:能够疾速挑选一日、一周、一月和一年时候段

日期挑选:分为摆布组织,左边时实在日期,右边时完毕日期

操纵按钮:挑选好日期后,能够经由过程点击肯定或许作废来封闭面板

3、QDateWidget、QDateContent

上边说了QDatePanel是日期挑选面板,个中日期挑选部份就是由摆布两部份构成,实在离别就是一个QDateWidget,以下图所示

QDateContent类是主要的日期盘算和绘制类,被QDateWidget包裹了一层,并增加上了年和月的操纵按钮。

下面主要引见下QDateContent类的完成,起首来看下声明文件

因为篇幅缘由照样解释了一大部份代码

class QDateContent : public QWidget
{
    ...
signals:
    void DateClicked(unsigned short year, unsigned short month, unsigned short day);

public:
    void SetSelectDate(unsigned short year, unsigned short month, unsigned short day);
    void GetSelectDate(unsigned short & year, unsigned short & month, unsigned short & day);
    void SetDate(unsigned short year, unsigned short month, unsigned short day);
    void GetDate(unsigned short & year, unsigned short & month, unsigned short & day);

    //设置关联日期
    void SetRelationDate(QDateContent * content);

public slots :
    void PreviousMonth();//上一月
    void NextMonth();//下一月
    void PreviousYear();//上一年
    void NextYear();//下一年
    ...
private:
    struct QDateContentPrivate;
    QDateContentPrivate * d_ptr;
};

切换月份和年份的接口代码中已包含了解释,其他Set和Get接口看称号基础也能邃晓,QDateContent类的代码量照样比较大的,下面我们主要来看绘制部份,个中有3个比较主要的点绘制头绘制数字绘制选中

绘制头

该绘制模块主如果绘制表头,也就是周日、周一如许的字段,绘制的位置时经由过程私有函数GetColumnLeft和GetColumnRight猎取。

void QDateContent::DrawWeek(QPainter & painter)
{
    //  QString aText[7] = { STR("周日"), STR("周一"), STR("周二"), STR("周三"), STR("周四"), STR("周五"), STR("周六") };
    QString aText[7] = { STR("日"), STR("一"), STR("二"), STR("三"), STR("四"), STR("五"), STR("六") };

    painter.save();
    painter.setFont(d_ptr->weekFont);
    QFontMetrics fm(d_ptr->weekFont);
    int height = fm.height();

    //painter.fillRect(d_ptr->GetColumnLeft(0), d_ptr->topBorder, d_ptr->GetColumnRight(6) - 3, d_ptr->topBorder + height, QColor(20, 22, 23));

    for (int i = 0; i < 7; ++i)
    {
        int left = d_ptr->GetColumnLeft(i);
        int right = d_ptr->GetColumnRight(i);
        QRect rect(left, d_ptr->topBorder, right - left, height);
        painter.setPen(QColor("#838D9E"));

        painter.drawText(rect, Qt::AlignCenter, aText[i]);
    }

    painter.restore();
}

绘制数字

绘制数字和绘制题目道理基础一致,位置信息都是运用GetColumnLeft和GetColumnRight猎取,差别的是,绘制数字时还须要绘制分外的选中状况、悬浮状况

因为是绘制函数,因而有一些数据盘算是经由过程整理好的,比如说须要绘制的数字当前行数当月第一天周几等等

因为绘制篇幅缘由,照样只保存主要逻辑

void QDateContent::DrawDay(QPainter & painter)
{
    painter.save();

    for (int column = 0; column < d_ptr->m_column_count; ++column)
    {
        int column_left = d_ptr->GetColumnLeft(column);
        int column_right = d_ptr->GetColumnRight(column);
        for (int row = 0; row < d_ptr->m_row_count; ++row)
        {
            int index = row * d_ptr->m_column_count + column;
            QRect & rcTmp = d_ptr->m_aRect[index];
            tDayFlag & flag = d_ptr->m_aDayFlag[index];
            flag.m_chEnable = (column != 0 && column != 6) ? true : false;

            bool selected = d_ptr->MatchRealDate(flag);
            if (selected)
            {
                QPainterPath path;
                path.addEllipse(QRectF(rcTmp).center(), 12, 12);
                painter.fillPath(path, QColor("#218CF2"));
            }

            painter.drawText(rcTmp, Qt::AlignCenter, QString::number(flag.m_chFlagD));

            painter.restore();
        }
    }

    painter.restore();
}

绘制选中

以下代码是绘制选中时的程度背景色,绘制代码比较简朴,庞杂的处所主要有2个:

  1. 盘算当前日期是不是在挑选日期段当中,返回status
  2. 修正第一步返回的status

因为绘制篇幅缘由,照样只保存主要逻辑

以下代码是精简事后的绘制选中背景色,看起来照样很长,不过大体上是分下面这几步

  1. 依据当前年月日返回status,示意当前day是不是在挑选的最先和挑选的完毕日期之间
  2. 依据所处列和day修正第一步返回的status
  3. 依据status调解要绘制的外形
  4. 绘制背景色

下面是主要的绘制流程,代码就不细讲了,人人能够自行浏览

void QDateContent::DrawSelectedBackground(QPainter & painter)
{
    painter.save();

    for (int column = 0; column < d_ptr->m_column_count; ++column)
    {
        for (int row = 0; row < d_ptr->m_row_count; ++row)
        {
            tDayFlag & flag = d_ptr->m_aDayFlag[index];

            if (little)
            {
                status = d_ptr->GetSelectedStatus(d_ptr->m_wYear, d_ptr->m_wMonth, d_ptr->m_wDay, d_ptr->m_sYear
                    , d_ptr->m_sMonth, flag.m_chFlagD, year, month, day);
            }
            else
            {
                status = d_ptr->GetSelectedStatus(year, month, day, d_ptr->m_sYear
                    , d_ptr->m_sMonth, flag.m_chFlagD, d_ptr->m_wYear, d_ptr->m_wMonth, d_ptr->m_wDay);
            }

            //修正数据
            CorrentStatus(status, column, flag.m_chFlagD);

            if (status == 0)
            {
                continue;
            }
            QRect rect = rcTmp.adjusted(0, 3, 0, -3);
            if (rect.height() < 15)
            {
                rect.setHeight(15);
                rect.moveCenter(rcTmp.center());
            }
            if (status == 2)
            {
                rect.adjust(-4, 0, 4, 0);
                painter.drawRect(rect);
            }
            else if (status == 1)//只要左半边
            {
                rect.adjust(-4, 0, -4, 0);
                painter.drawRoundedRect(rect, rect.height() / 2, rect.height() / 2);
                painter.drawRect(rect.adjusted(0, 0, -rect.height() / 2, 0));
            }
            else if (status == 3)
            {
                rect.adjust(4, 0, 4, 0);
                painter.drawRoundedRect(rect, rect.height() / 2, rect.height() / 2);
                painter.drawRect(rect.adjusted(rect.height() / 2, 0, 0, 0));
            }
            else if (status == 5)
            {
                rect.adjust(4, 0, -4, 0);
                painter.drawRoundedRect(rect, rect.height() / 2, rect.height() / 2);
            }
        }
    }

    painter.restore();
}

4、 调理绘制

末了就是绘制的递次,这里肯定要注意,肯定得线绘制背景色,如果是末了绘制的话会盖住当前绘制的笔墨和选中状况。

void QDateContent::paintEvent(QPaintEvent * event)
{
    QDate date = QDate::currentDate();
    d_ptr->m_tYear = date.year();
    d_ptr->m_tMonth = date.month();
    d_ptr->m_tDay = date.day();

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);

    //painter.drawRect(rect());

    d_ptr->ResetDayFlag();

    DrawSelectedBackground(painter);

    DrawWeek(painter);

    DrawDay(painter);
}

五、相干文章

自定义日历(一)

自定义日历(二)

自定义日历(三))

Qt之模仿窗口落空核心隐蔽

值得一看的优异文章:

  1. 财联社-产物展现
  2. 广联达-产物展现
  3. Qt定制控件列表
  4. 牛逼哄哄的Qt库





如果您以为文章不错,无妨给个 打赏,写作不容易,感谢列位的支撑。您的支撑是我最大的动力,感谢!!!













很主要--转载声明

  1. 本站文章无迥殊申明,皆为原创,版权所有,转载时请用链接的体式格局,给出原文出处。同时写上原作者:朝十晚八 or Twowords

  2. 如要转载,请原文转载,如在转载时修正本文,请事前示知,推辞在转载时经由过程修正本文到达有利于转载者的目标。

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
自定义日历(四)-区间挑选控件

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282081.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>