自定義日歷(三)


一、回顧

    本篇文章之前我想先回顧一下前邊我門所講述的兩篇關於自定義日歷的文章,文章的鏈接在后續相關鏈接中都可以看到,第一篇文章中講的是使用QLabel控件拼湊的日歷,好理解,但是性能較第二種方式差,第二種日歷的位置區域和日期文字都是在內存中計算,然后繪制在一個窗口上,性能上肯定沒問題。本篇文章依然沿用和自定義日歷(二)一樣使用內容計算位置和日期文字。

二、效果預覽

    如圖1所示,可以記錄住當前所選擇的日期的日歷控件,沒有qss美化,比較丑

圖1 自定義日歷

三、實現原理

    看這一節之前,如果有興趣的同學可以先下載demo,然后對照着示例代碼看這一小節效果更好。

    首先我先介紹幾個類:

  • DrawDateTime:日期內容窗口,主要負責繪制當月日期和左右兩個月部分日期
  • CalendarWidget:下拉框預覽窗口,包含了日期頭部和日期內容兩部分
  • DropDataControl:日歷控件類,對外導出類,可以直接被外部使用。包含當前日期和按鈕,點擊按鈕可以彈出下拉框

1、DrawDateTime

  關於繪制日期內容窗口請參考自定義日歷(二)文章,在此我只簡述一下內容有所改動的地方。

  a、添加記錄選中天的數據項,並修改MatchRealDate函數,具體代碼如下:

 1 //選中天
 2 unsigned short m_wYear;
 3 unsigned short m_wMonth;
 4 unsigned short m_wDay;
 5 
 6 //計算日歷位置
 7 unsigned short m_sYear;
 8 unsigned short m_sMonth;
 9 unsigned short m_sDay;
10 
11 bool MatchRealDate(tDayFlag df)
12 {
13     if (df.m_chFlagD == m_wDay && m_sMonth == m_wMonth)//如果當前月份等於選中月份才認為是當前選中天
14     {
15         return true;
16     }
17     return false;
18 }

  b、鼠標按下時,更新當前選中天

 1 void DrawDateTime::mousePressEvent(QMouseEvent * event)
 2 {
 3     if (event->button() == Qt::LeftButton)
 4     {
 5         int cur = GetIndex(event->pos());
 6         if (cur == -1)
 7         {
 8             return;
 9         }
10         tDayFlag & flag = d_ptr->m_aDayFlag[cur];
11 
12         unsigned short year = d_ptr->m_sYear, month = d_ptr->m_sMonth;
13         if (flag.m_chFlagM == -1)
14         {
15             d_ptr->GetPreviousMonth(year, month);
16         }
17         else if (flag.m_chFlagM == 1)
18         {
19             d_ptr->GetNextMonth(year, month);
20         }
21         bool b = (d_ptr->m_wDay != flag.m_chFlagD || month != d_ptr->m_wMonth || year != d_ptr->m_wYear);
22         if (b)
23         {
24             d_ptr->m_wDay = flag.m_chFlagD;
25             d_ptr->m_wMonth = month;
26             d_ptr->m_wYear = year;
27             update();
28         }
29 
30         DataClicked(year, month, d_ptr->m_wDay);//發出信號,用於更新ui界面
31     }
32 }

2、CalendarWidget

  下拉框預覽窗口,包含日期窗口頭,和日期繪制界面。當日期繪制界面發出DataClicked信號時,修改頭部當前年、月,並通知DropDataControl窗口修改日期。按下表頭的上一月和下一月時,修改表頭信息,並通知日期繪制界面修改界面數據,關鍵代碼如下:

 1 d_ptr->m_pDataView = new DrawDateTime;
 2 connect(d_ptr->m_pDataView, &DrawDateTime::DataClicked, this, [this](unsigned short year, unsigned short month, unsigned short day){
 3     emit DataClicked(year, month, day);//通知DropDataControl窗口修改日期
 4     d_ptr->m_pMonth->setText(dataDescribe(year, month));//修改頭部當前年、月
 5 //    setHidden(true);
 6 });
 7 
 8 connect(d_ptr->m_pPrevisou, &QPushButton::clicked, this, [this]{
 9     d_ptr->m_pDataView->PreviousMonth();//並通知日期繪制界面修改界面數據
10     d_ptr->m_pDataView->GetDate(d_ptr->m_wYear, d_ptr->m_wMonth, d_ptr->m_wDay);
11     d_ptr->m_pMonth->setText(dataDescribe(d_ptr->m_wYear, d_ptr->m_wMonth));//修改頭部當前年、月
12 });
13 connect(d_ptr->m_pNext, &QPushButton::clicked, this, [this]{
14     d_ptr->m_pDataView->NextMonth();//並通知日期繪制界面修改界面數據
15     d_ptr->m_pDataView->GetDate(d_ptr->m_wYear, d_ptr->m_wMonth, d_ptr->m_wDay);
16     d_ptr->m_pMonth->setText(dataDescribe(d_ptr->m_wYear, d_ptr->m_wMonth));//修改頭部當前年、月
17 });

3、DropDataControl

  日期空間,對外導出類,可以被外部直接使用。關於布局,我就不細說了,貼下關於connect,代碼如下:

 1 connect(d_ptr->m_pDropButton, &QPushButton::clicked, this, &DropDataControl::DropButtonClicked);
 2 connect(d_ptr->m_pDropWidget, &CalendarWidget::DataClicked, this, [this](unsigned short year, unsigned short month, unsigned short day){
 3     d_ptr->m_pText->setText(dataDescribe(year, month, day));//修改QLineEdit文本數據
 4 });
 5 
 6 d_ptr->m_pDropWidget->setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);//彈出式菜單
 7 
 8 void DropDataControl::DropButtonClicked()
 9 {
10     d_ptr->m_pDropWidget->move(mapToGlobal(rect().bottomLeft()));
11     d_ptr->m_pDropWidget->show();
12 }

    上述代碼第6行說明了彈出式窗口是具有Qt::Popup屬性,呵呵,具有這個屬性的窗口都會阻塞主事件循環,也就這個窗口是一個模態框,具體請看圖2關於這個屬性的說明,紅色矩形框中的文字意思就是:這是模態

圖2 Qt::Popup說明

    如果不想要這個窗口是模態的,那么就不能設置Qt::Popup屬性,具體可以參見Qt之模擬窗口失去焦點隱藏文章,這篇文章里簡述了怎么讓一個窗口失去焦點隱藏的方法,肯定不完善,需要自己在根據業務去控制。好了,本篇文章到此就結束了。

四、示例下載

  Qt之自繪制日歷控件(三)

五、相關鏈接

  自定義日歷(一)

  自定義日歷(二)

  Qt之模擬窗口失去焦點隱藏

如果您覺得文章不錯,不妨給個打賞,寫作不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!! 

 

  


很重要--轉載聲明

  1. 本站文章無特別說明,皆為原創,版權所有,轉載時請用鏈接的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords
  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM