最近一直比較忙,根本沒時間記錄自己想寫的東西,趁著國慶小長假,我自己也列出了想記錄的一些小東西,方便他人借鑒,也方便我自己學習。廢話不多說,我先來貼上我自己的demo展示圖,這個demo比較復雜,我可能會分兩篇博客來講述。與其說是因為demo復雜,還不如說是這個月份是按照完全不同的兩種思路來展示。
月份展示效果
如上圖所示,這是兩種日歷展示形式,上方的日歷是用label拼成,下方的日歷是用一個窗口繪制而成,完全不同的兩種路線,各有優(yōu)缺點。接下來我將會分別介紹這兩種月份的實現(xiàn)過程。
這兩種日歷的優(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),我們的程序處理才會變得簡單。
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:獲取下一個月份的年和日
區(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 }
在自繪制日歷的時候,點擊位置或者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ū)域,他在合適的時機就會重置。
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 }
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 }
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 }
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 }
日期點擊時,如果點擊的是上一個月份的日期,則把當前月份切換到上一個月;如果點擊的是下一個月的日期,則把當前月份切換到下一個月;否則當前月份不變,當前點擊的日期顏色變成白色。
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學習資料+視頻教程~「鏈接」
本文所講述的這種日歷在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 | 顯示日歷 |
CalendarDay | calendar 控件中的一天 |
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)】
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。