整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          自定義日歷(一)

          自定義日歷(一)

          、概要

          最近一直比較忙,根本沒時間記錄自己想寫的東西,趁著國慶小長假,我自己也列出了想記錄的一些小東西,方便他人借鑒,也方便我自己學習。廢話不多說,我先來貼上我自己的demo展示圖,這個demo比較復雜,我可能會分兩篇博客來講述。與其說是因為demo復雜,還不如說是這個月份是按照完全不同的兩種思路來展示。

          月份展示效果

          如上圖所示,這是兩種日歷展示形式,上方的日歷是用label拼成,下方的日歷是用一個窗口繪制而成,完全不同的兩種路線,各有優(yōu)缺點。接下來我將會分別介紹這兩種月份的實現(xiàn)過程。

          2、優(yōu)缺點比較

          這兩種日歷的優(yōu)缺點我總結(jié)了一個簡單的表格,如下表:


          label平湊

          widget自繪

          優(yōu)點

          實現(xiàn)思路簡單容易理解,每天都是一個label

          繪制不同于其他天比較方便(藍點)

          實現(xiàn)稍微復雜,每天的位置需要自己計算

          相對于第一種相率高,內(nèi)存占用率低,事件處理層級少

          窗口放大縮小效率高

          背景色漸變?nèi)菀讓崿F(xiàn)

          缺點

          每天都是一個label,對性能有影響

          窗口大小變化時麻煩

          背景色漸變難以實現(xiàn)

          widget每次整個重繪,每一天上的內(nèi)容繪制比較難以計算

          兩種月份優(yōu)缺點比較

          本片文字我重點介紹下第二種日歷的繪制,也就是整個窗口重新繪制,這種日歷的實現(xiàn)難點就在于窗口事件的處理上,設(shè)計了好的數(shù)據(jù)結(jié)構(gòu),我們的程序處理才會變得簡單。

          3、數(shù)據(jù)結(jié)構(gòu)設(shè)計

          1 struct tDayFlag
          2 {
          3     signed char m_chFlagM; // -1 pre 0 cur 1 next
          4     unsigned short m_chFlagD; // day num
          5 };

          這個結(jié)構(gòu)負責存儲每一天的信息,m_chFlagM這個字段表示是否是當前月份的,-1:上一個月,1:下一個月,0表示當前月份;m_chFlagD存儲是一個月中的那一天。
          接下來是一個impl接口類
          DrawDateTimePrivate,這個類中存儲了大量的計算信息,負責日歷的數(shù)據(jù)計算和比較

            1 struct DrawDateTime::DrawDateTimePrivate
            2 {
            3 public:
            4     DrawDateTimePrivate(DrawDateTime * s)
            5         : m_Self(s)
            6         //, m_pOnChanged(NULL)
            7     {
            8         m_aRect=new QRect[m_column_count * m_row_count];
            9         m_aDayFlag=new tDayFlag[m_column_count * m_row_count];
           10         m_sOverIndex=-1;
           11 
           12         SYSTEMTIME st;
           13         GetLocalTime(&st);
           14         m_wYear=st.wYear;
           15         m_wMonth=st.wMonth;
           16         m_wDay=st.wDay;
           17     }
           18 
           19     ~DrawDateTimePrivate()
           20     {
           21         delete []m_aRect;
           22         delete []m_aDayFlag;
           23     }
           24 
           25 public:
           26     unsigned int GetColumnLeft(int column)
           27     {
           28         unsigned int left=(width - leftBorder - rightBorder + columnSpace) / m_column_count * column + leftBorder;
           29 
           30         return left;
           31     }
           32 
           33     unsigned int GetColumnRight(int column)
           34     {
           35         if (column < 0 || column > m_column_count)
           36         {
           37             column=0;
           38         }
           39 
           40         //總寬度-左border-由border-(m_column_count-1)*列間隙
           41         unsigned int itemWidth=(width - leftBorder - rightBorder - (m_column_count - 1) * columnSpace) / m_column_count;
           42         unsigned int right=GetColumnLeft(column) + itemWidth;
           43 
           44         return right;
           45     }
           46 
           47     unsigned int GetRowTop(int row)
           48     {
           49         QFontMetrics fm(weekFont);
           50         int weekHeight=fm.height();
           51 
           52         unsigned int top=(height - topBorder - bottomBorder - weekHeight + rowSpace) / m_row_count * row
           53             + space + weekHeight;
           54 
           55         return top;
           56     }
           57 
           58     unsigned int GetRowBottom(int row)
           59     {
           60         if (row < 0 || row > m_row_count)
           61         {
           62             row=0;
           63         }
           64 
           65         QFontMetrics fm(weekFont);
           66         int weekHeight=fm.height();
           67 
           68         //總高度-上border-下border-(m_row_count-1)*行間隙-week高
           69         unsigned int itemHeight=(height - topBorder - bottomBorder - weekHeight - space - (m_row_count - 1) * rowSpace) / m_row_count;
           70         unsigned int bottom=GetRowTop(row) + itemHeight;
           71 
           72         return bottom;
           73     }
           74 
           75 public:
           76     int columnSpace=5;
           77     int rowSpace=5;
           78 
           79     int leftBorder=10;
           80     int rightBorder=10;
           81     int topBorder=5;
           82     int bottomBorder=5;
           83 
           84     int width=100;
           85     int height=80;
           86 
           87     int space=10;//周名稱和天之間距離
           88 
           89     int m_column_count=7;//列數(shù)
           90     int m_row_count=6;//行數(shù)
           91 
           92     QFont weekFont=QFont(STR("微軟雅黑", 14));
           93     QFont dayFont;
           94 
           95 public:
           96     DrawDateTime * m_Self;
           97 
           98     //    IDateInfoChangedNotify * m_pOnChanged;
           99 
          100     unsigned short m_wYear;
          101     unsigned short m_wMonth;
          102     unsigned short m_wDay;
          103 
          104     tDayFlag * m_aDayFlag;    // 各個按鈕日期號
          105     QRect * m_aRect;        // 各個按鈕區(qū)域
          106     short m_sOverIndex;    // 熱點按鈕下標
          107 
          108     bool MatchRealDate(tDayFlag df)
          109     {
          110         if (df.m_chFlagD==m_wDay && 0==df.m_chFlagM)
          111         {
          112             return true;
          113         }
          114         return false;
          115     }
          116 
          117     //重置當前月份上的日期flag及顯示的數(shù)據(jù)
          118     void ResetDayFlag()
          119     {
          120         unsigned short  preY, preM;
          121         GetPreviousMonth(preY, preM);
          122 
          123         int nPreMonDays=DayofMonth(preY, preM);
          124         int nCurMonDays=DayofMonth(m_wYear, m_wMonth);
          125         int week=CalDayofWeek(m_wYear, m_wMonth, 1);
          126 
          127         int index=0;
          128 
          129         for (int i=0; i < week; ++i, index++)
          130         {
          131             m_aDayFlag[index].m_chFlagM=-1;
          132             m_aDayFlag[index].m_chFlagD=(nPreMonDays - week + 1) + i;
          133         }
          134 
          135         for (int i=0; i < nCurMonDays; ++i, index++)
          136         {
          137             m_aDayFlag[index].m_chFlagM=0;
          138             m_aDayFlag[index].m_chFlagD=i + 1;
          139         }
          140 
          141         m_row_count=index / 7 + (index % 7==0 ? 0 : 1);
          142 
          143         for (int j=1; index < m_column_count * m_row_count; ++j, ++index)
          144         {
          145             m_aDayFlag[index].m_chFlagM=1;
          146             m_aDayFlag[index].m_chFlagD=j;
          147         }
          148     }
          149 
          150     //獲取上一個月的年和月份
          151     void GetPreviousMonth(unsigned short & preYear, unsigned short & preMonth)
          152     {
          153         if (m_wMonth > 1)
          154         {
          155             preYear=m_wYear;
          156             preMonth=m_wMonth - 1;
          157         }
          158         else
          159         {
          160             preYear=m_wYear - 1;
          161             preMonth=12;
          162         }
          163     }
          164 
          165     //獲取下一個月的年和月份
          166     void GetNextMonth(unsigned short & nextYear, unsigned short & nextMonth)
          167     {
          168         if (m_wMonth >=12)
          169         {
          170             nextYear=m_wYear + 1;
          171             nextMonth=1;
          172         }
          173         else
          174         {
          175             nextYear=m_wYear;
          176             nextMonth=m_wMonth + 1;
          177         }
          178     }
          179 };
          GetColumnLeft:獲取指定列的左邊界
          GetColumnRight:獲取指定列的右邊界
          GetRowTop:獲取指定行的上邊界
          GetRowBottom:獲取指定行的下邊界
          
          MatchRealDate:檢測給定日期是否是當前天
          ResetDayFlag:重置impl中的內(nèi)存數(shù)據(jù)
          GetPreviousMonth:獲取上一個月份的年和日
          GetNextMonth:獲取下一個月份的年和日

          4、區(qū)域生成

          區(qū)域生成顧名思義就是生成日期的繪制區(qū)域,這個需要根據(jù)當前窗口的大小、列間距、行間距等信息來計算每一天的矩形區(qū)域,當有月份切換時需要重新計算該信息,如果覺著這個過程對性能沒有影響可以在每次整個繪制的時候都重新計算,這樣有助于程序在出錯時自動恢復。關(guān)于區(qū)域自動生成,在上一個小節(jié)我們已經(jīng)給出了接口解釋,接下來我將貼出實現(xiàn)代碼,并做相應(yīng)解釋

           1 //重置當前月份上的日期flag及顯示的數(shù)據(jù)
           2     void ResetDayFlag()
           3     {
           4         unsigned short  preY, preM;
           5         GetPreviousMonth(preY, preM);
           6 
           7         int nPreMonDays=DayofMonth(preY, preM);
           8         int nCurMonDays=DayofMonth(m_wYear, m_wMonth);
           9         int week=CalDayofWeek(m_wYear, m_wMonth, 1);
          10 
          11         int index=0;
          12 
          13         for (int i=0; i < week; ++i, index++)//重置上一個月份的日期
          14         {
          15             m_aDayFlag[index].m_chFlagM=-1;
          16             m_aDayFlag[index].m_chFlagD=(nPreMonDays - week + 1) + i;
          17         }
          18 
          19         for (int i=0; i < nCurMonDays; ++i, index++)//重置本月份的日期
          20         {
          21             m_aDayFlag[index].m_chFlagM=0;
          22             m_aDayFlag[index].m_chFlagD=i + 1;
          23         }
          24 
          25         m_row_count=index / 7 + (index % 7==0 ? 0 : 1);//更新行數(shù)
          26 
          27         for (int j=1; index < m_column_count * m_row_count; ++j, ++index)//重置下一個月份的日期
          28         {
          29             m_aDayFlag[index].m_chFlagM=1;
          30             m_aDayFlag[index].m_chFlagD=j;
          31         }
          32     }

          5、點擊位置是哪一天

          在自繪制日歷的時候,點擊位置或者hover位置是哪一個日期判斷是非常重要的,這個涉及到整個日歷是否是有一個友好的交互。在開始做這個基于widget繪制日的時候我也迷茫過,覺得判斷點擊位置是哪一天非常困難,實時也是這樣的,判斷起來是非常困難的,直到后來我看到了一個網(wǎng)友的數(shù)據(jù)結(jié)構(gòu)設(shè)計,原來這個判斷是如此的簡單,不過簡單的判斷都是基于一個優(yōu)秀的結(jié)構(gòu)設(shè)計,判斷代碼如下:

           1 int DrawDateTime::GetIndex(const QPoint & point)
           2 {
           3     int id=-1;
           4     for (int i=0; i < _ptr->m_row_count * _ptr->m_column_count + 4; ++i)
           5     {
           6         QRect & rc=_ptr->m_aRect[i];
           7         if (point.x() > rc.left() && point.x()< rc.right()
           8             && point.y() > rc.top() && point.y() < rc.bottom())
           9         {
          10             id=i;
          11             break;
          12         }
          13     }
          14 
          15     return id;
          16 }

          上述判斷只用了一個循環(huán)就可以判斷出點擊位置是在那個日期上,_ptr->m_aRect這個結(jié)構(gòu)存儲了所有日期的矩形區(qū)域,他在合適的時機就會重置。

          6、周內(nèi)容繪制

           1 void DrawDateTime::DrawWeek(QPainter & painter)
           2 {
           3     QString aText[7]={ STR("周日"), STR("周一"), STR("周二"), STR("周三"), STR("周四"), STR("周五"), STR("周六") };
           4 
           5     painter.save();
           6     painter.setFont(_ptr->weekFont);
           7     QFontMetrics fm(_ptr->weekFont);
           8     int height=fm.height();
           9     for (int i=0; i < 7; ++i)
          10     {
          11         int left=_ptr->GetColumnLeft(i);
          12         int right=_ptr->GetColumnRight(i);
          13         QRect rect(left, _ptr->topBorder, right - left, height);
          14         painter.drawRect(rect);
          15         painter.drawText(rect, Qt::AlignCenter, aText[i]);
          16     }
          17     painter.restore();
          18 }

          7、日期內(nèi)容繪制

           1 void DrawDateTime::DrawDay(QPainter & painter)
           2 {
           3     _ptr->ResetDayFlag();
           4 
           5     painter.save();
           6 
           7     QFontMetrics fm(_ptr->weekFont);
           8     int weekHeight=fm.height();
           9 
          10     for (int column=0; column < _ptr->m_column_count; ++column)
          11     {
          12         int column_left=_ptr->GetColumnLeft(column);
          13         int column_right=_ptr->GetColumnRight(column);
          14         for (int row=0; row < _ptr->m_row_count; ++row)
          15         {
          16             int index=row * _ptr->m_column_count + column;
          17             QRect & rcTmp=_ptr->m_aRect[index];
          18             tDayFlag & flag=_ptr->m_aDayFlag[index];
          19 
          20             rcTmp.setLeft(column_left);
          21             rcTmp.setRight(column_right);
          22             rcTmp.setTop(_ptr->GetRowTop(row));
          23             rcTmp.setBottom(_ptr->GetRowBottom(row));
          24 
          25             QPainterPath path;
          26             path.addRoundRect(rcTmp, 25);
          27 
          28             if (index==_ptr->m_sOverIndex)//hover時背景色
          29             {
          30                 painter.fillPath(path, QColor(144, 151, 151));
          31             }
          32 
          33             painter.save();
          34             if (-1==flag.m_chFlagM || 1==flag.m_chFlagM)
          35             {
          36                 painter.setPen(QColor(Qt::blue));
          37             }
          38             else
          39             {
          40                 if (_ptr->MatchRealDate(flag))
          41                 {
          42                     painter.setPen(QColor(Qt::red));
          43                 }
          44                 else if (index==_ptr->m_sOverIndex)
          45                 {
          46                     painter.setPen(QColor(Qt::white));
          47                 }
          48                 else
          49                 {
          50 
          51                 }
          52             }
          53             painter.setOpacity(0.5);//繪制半透明度字
          54             painter.drawText(rcTmp, Qt::AlignCenter, QString::number(flag.m_chFlagD));
          55 
          56             painter.restore();
          57 
          58             painter.drawPath(path);
          59         }
          60     }
          61 
          62     painter.restore();
          63 }

          8、月份切換

           1 void DrawDateTime::PreviousMonth()//上一個月份
           2 {
           3     unsigned short year, month;
           4     _ptr->GetPreviousMonth(year, month);
           5 
           6     int acturlDays=DayofMonth(year, month);
           7     if (acturlDays < _ptr->m_wDay)
           8     {
           9         _ptr->m_wDay=acturlDays;
          10     }
          11     SetDate(year, month, _ptr->m_wDay);
          12 
          13     update();
          14 }
          15 
          16 void DrawDateTime::NextMonth()//下一個月份
          17 {
          18     unsigned short year, month;
          19     _ptr->GetNextMonth(year, month);
          20 
          21     int acturlDays=DayofMonth(year, month);
          22     if (acturlDays < _ptr->m_wDay)
          23     {
          24         _ptr->m_wDay=acturlDays;
          25     }
          26     SetDate(year, month, _ptr->m_wDay);
          27 
          28     update();
          29 }

          9、日期點擊時效果

           1 void DrawDateTime::mousePressEvent(QMouseEvent * event)
           2 {
           3     if (event->button()==Qt::LeftButton)
           4     {
           5         int cur=GetIndex(event->pos());
           6         tDayFlag & flag=_ptr->m_aDayFlag[cur];
           7         
           8         unsigned short year=_ptr->m_wYear, month=_ptr->m_wMonth;
           9         if (flag.m_chFlagM==-1)
          10         {
          11             _ptr->GetPreviousMonth(year, month);
          12         }
          13         else if (flag.m_chFlagM==1)
          14         {
          15             _ptr->GetNextMonth(year, month);
          16 
          17         }
          18         bool b=(_ptr->m_wDay !=flag.m_chFlagD || month !=_ptr->m_wMonth || year !=_ptr->m_wYear);
          19         if (b)
          20         {
          21             _ptr->m_wDay=flag.m_chFlagD;
          22             _ptr->m_wMonth=month;
          23             _ptr->m_wYear=year;
          24             update();
          25         }
          26     }
          27 }

          日期點擊時,如果點擊的是上一個月份的日期,則把當前月份切換到上一個月;如果點擊的是下一個月的日期,則把當前月份切換到下一個月;否則當前月份不變,當前點擊的日期顏色變成白色。

          10、鼠標移動時效果

           1 void DrawDateTime::mouseMoveEvent(QMouseEvent * event)
           2 {
           3     int cur=GetIndex(event->pos());
           4     bool b=(cur !=_ptr->m_sOverIndex);
           5     if (b)
           6     {
           7         int previousHover=_ptr->m_sOverIndex;
           8         _ptr->m_sOverIndex=cur;
           9         update(_ptr->m_aRect[cur]);
          10         update(_ptr->m_aRect[previousHover]);
          11     }
          12 
          13     QWidget::mouseMoveEvent(event);
          14 }

          鼠標hover時,修改當前所hover的日期,然后在重新繪制時,如果是hover的日期,則繪制顏色變?yōu)?/span>QColor(144, 151, 151)

          點擊領(lǐng)取Qt學習資料+視頻教程~「鏈接」

          11、實現(xiàn)動畫

          本文所講述的這種日歷在demo中實現(xiàn)時沒有使用動畫來切換月份,但是用label拼湊的日歷使用了動畫來切換月份,如果有興趣的同學可以把本文后面提供的demo下載下來,自行進行修改,修改的時候可以參考label拼湊月份的動畫,由于label拼湊的月份實現(xiàn)起來更為繁瑣,因此本片文章就不繼續(xù)講解了,在下一篇文章中我將講解一些關(guān)鍵的實現(xiàn)思路和不足。順便提一句,支持動畫切換月份的日歷控件時在一個窗口的基礎(chǔ)上切換的,感興趣的同學也可以實現(xiàn)5個月份的切換,就像一些音樂播放器主頁上的音樂提示一樣,是一個輪播的形式。例如網(wǎng)易音樂

          網(wǎng)易輪播

          日歷同意可以以這樣的形式來切換,這樣的功能我已經(jīng)實現(xiàn)了,如果感興趣的同學可以私聊,demo中的代碼在完善優(yōu)化下,就可以做出這個效果,基于widget完全繪制的日歷可能更合適這樣的切換,label的堆砌在切換的時候可能會有效率的問題,這就取決于你的機器了,一般的機器還都是沒有問題的,除非你要做對效率要求很高的程序。

          關(guān)于label拼湊的日歷我將會在自定義日歷(二)給出詳細講解

          作者:朝十晚八 or Twowords

          轉(zhuǎn)載:https://www.cnblogs.com/swarmbees/p/5927823.html

          eb 服務(wù)器控件是服務(wù)器可理解的特殊 ASP.NET 標簽。


          Web 服務(wù)器控件

          就像 HTML 服務(wù)器控件,Web 服務(wù)器控件也是在服務(wù)器上創(chuàng)建的,它們同樣需要 runat="server" 屬性才能生效。然而,Web 服務(wù)器控件沒有必要映射任何已存在的 HTML 元素,它們可以表示更復雜的元素。

          創(chuàng)建 Web 服務(wù)器控件的語法是:

          <asp:control_name id="some_id" runat="server" />

          Web 服務(wù)器控件描述
          AdRotator顯示一個圖形序列
          Button顯示下壓按鈕
          Calendar顯示日歷
          CalendarDaycalendar 控件中的一天
          CheckBox顯示復選框
          CheckBoxList創(chuàng)建多選的復選框組
          DataGrid顯示 grid 中數(shù)據(jù)源的字段
          DataList通過使用模版顯示數(shù)據(jù)源中的項目
          DropDownList創(chuàng)建下拉列表
          HyperLink創(chuàng)建超鏈接
          Image顯示圖像
          ImageButton顯示可點擊的圖像
          Label顯示可編程的靜態(tài)內(nèi)容(使您對其內(nèi)容應(yīng)用樣式)
          LinkButton創(chuàng)建超鏈接按鈕
          ListBox創(chuàng)建單選或多選的下拉列表
          ListItem創(chuàng)建列表中的一個項目
          Literal顯示可編程的靜態(tài)內(nèi)容(無法使您對其內(nèi)容應(yīng)用樣式)
          Panel為其他控件提供容器
          PlaceHolder為由代碼添加的控件預留空間
          RadioButton創(chuàng)建單選按鈕
          RadioButtonList創(chuàng)建單選按鈕組
          BulletedList創(chuàng)建項目符號格式的列表
          Repeater顯示綁定到控件的項目的重復列表
          Style設(shè)置控件的樣式
          Table創(chuàng)建表格
          TableCell創(chuàng)建表格單元格
          TableRow創(chuàng)建表格行
          TextBox創(chuàng)建文本框
          Xml顯示 XML 文件或 XSL 轉(zhuǎn)換的結(jié)果

          ccess快速開發(fā)平臺一個一直被忽略的功能,即通用日期選擇器可以對日期進行選擇設(shè)置日期,可以選擇時間、選擇時分功能,之前一直有人問日期控件能不能選擇時間、選擇分鐘?現(xiàn)在把這個時間選取器的設(shè)置方法分享給大家學習一下。

          如果你還沒有下載Access快速開發(fā)平臺,則可以先下載一個空白版平臺打開測試一下該功能,Access開發(fā)平臺最新版下載地址:

          http://www.accessgood.com


          Access快速開發(fā)平臺時間選取器的設(shè)置步驟:

          1.文本框控件,單擊里面寫 =DatePickerFor([Text0],False)

          設(shè)為False 只選取日期


          2.日期選擇的顯示效果如下圖:


          3.文本框控件,單擊里面寫 =DatePickerFor([Text0],True)

          設(shè)為True 帶調(diào)時分


          4.日期時間、日期分鐘選擇的顯示效果如下圖:


          5.查看最終效果:對需要選擇設(shè)置日期、選擇設(shè)置時間的朋友來說,這樣看起來就方便多了。


          更多Access快速開發(fā)平臺自帶的函數(shù)\功能用法,請查閱幫助中心詳細了解!

          《盟威軟件快速開發(fā)平臺》在線幫助中心 (http://www.accessgood.com/help/Main.html)


          Access快速開發(fā)平臺--通用日期選擇器設(shè)置選擇日期、選擇時間、選擇時分、時間選取器的設(shè)置方法【Access軟件網(wǎng)】


          主站蜘蛛池模板: 国产成人精品无人区一区| 夜精品a一区二区三区| 国产午夜精品一区理论片飘花| 中文字幕一区二区区免| 亚洲一区中文字幕| 亚洲一区二区三区乱码在线欧洲| 日本激情一区二区三区| 男人的天堂精品国产一区| 国产免费一区二区三区在线观看| 91在线精品亚洲一区二区| 国产精品日韩欧美一区二区三区 | 国产伦精品一区二区免费| 一区二区在线视频| 国产视频福利一区| 丝袜人妻一区二区三区网站| 一区二区三区午夜| www亚洲精品少妇裸乳一区二区| 国产精品成人一区二区三区| 97精品一区二区视频在线观看| 伊人色综合一区二区三区影院视频| 久久久久人妻一区二区三区 | 日韩伦理一区二区| 成人毛片一区二区| 亚洲中文字幕久久久一区| 久久一本一区二区三区| 久久久91精品国产一区二区| 免费日本一区二区| 亚洲啪啪综合AV一区| 亚洲人成人一区二区三区| 久久一区二区精品综合| 亚洲电影一区二区| 国产免费一区二区三区| 国产精品香蕉在线一区| 国产成人免费一区二区三区| 日本精品视频一区二区| 国产成人片视频一区二区| 精品免费久久久久国产一区| 国产精品第一区第27页| 国产视频一区二区在线播放| 污污内射在线观看一区二区少妇 | 精品欧洲av无码一区二区|