디렉토리
원본 링크 : 사용자 정의 달력 (4 개) - 간격 선택 컨트롤
I. 개요
오래 오래 전, 및 일정에 대한 몇 가지 기사를 작성했습니다, 블로거에서 작성한 Qt는 네이티브 컨트롤, 달리 강한 방법으로 완전한 사용자 정의 할 수 있습니다 사용에 관심을 참조 할 수 있습니다 자기 사용자 정의 달력 (A) , 사용자 정의 달력 (2 개) 및 사용자 정의 달력 (c) 참조) .
이 문서는 여전히 여전히 더 멋진 효과를 가져다 자기 도장 방법을 사용하여, 우리의 달력 컨트롤을 작성하는 것을 계속한다. 이 기사의 제목를 봐 달성 할 수이 섹션 선택 달력 컨트롤 것을 이해 할 수 있어야한다.
둘째, 결과는 보여
도 효과는, 단순한 디스플레이의 효과를 따른다.
![](https://images.cnblogs.com/cnblogs_com/swarmbees/1458965/o_pick_date.gif)
Qt는 기본 QDateEdit와 Calendar 컨트롤은 예정대로 선택 패널을 가져다 버튼에 의해 트리거됩니다. 다음과 같은 차이점이 달력 날짜 선택 패널은 두 개의 작은 패널, 즉 시작과 끝 날짜로 구성되어 있다는 것입니다, 규칙은 다음과 같습니다
- 시작 날짜가 종료 날짜보다 작아야합니다
- 상단 버튼 빠른 복귀
- 우리는 선택한 기간에 배경 색상을 강조
- 선택한 날짜 확인 된 점에 블루 원
- 확인 버튼을 클릭하면 날짜 선택 패널을 닫습니다
셋째, 전체 구조
당신이 세부 사항을 설명하기 시작하기 전에 부문의 전체 구조에서 첫번째보기 아래 엔지니어링 구조이며,이 날짜 범위 선택 도구, 다음 네 가지 범주의 총을 달성하기 위해
![](https://images.cnblogs.com/cnblogs_com/swarmbees/1458965/o_date_segment.png)
다음은 클래스 4에 대한 설명입니다
- QDateContent : 하나의 달력 창
- QDateWidget는 : 하나의 달력 년 선택 창을 포함
- QDatePanel : 날짜 범위 선택 패널
- 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,如下图所示
![](https://images.cnblogs.com/cnblogs_com/swarmbees/1458965/o_date_widget.png)
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个:
- 计算当前日期是否在选择日期段当中,返回status
- 修正第一步返回的status
由于绘制篇幅原因,还是只保留主要逻辑
以下代码是精简过后的绘制选中背景色,看起来还是很长,不过大体上是分下面这几步
- 根据当前年月日返回status,表示当前day是否在选择的开始和选择的结束日期之间
- 根据所处列和day修改第一步返回的status
- 根据status调整要绘制的形状
- 绘制背景色
下面是主要的绘制流程,代码就不细讲了,大家可以自行阅读
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);
}
五、相关文章
值得一看的优秀文章:
如果您觉得文章不错,不妨给个 打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!
![]() |
![]() |
很重要--转载声明
本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords
如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。