(四十)c#Winform自定义控件-开关
程序员文章站
2022-07-01 13:54:39
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control 如果觉得写的还行,请点个 star 支持一下吧 欢迎前来交流探讨: 企鹅群568015492 目录 ......
前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
开源地址:
如果觉得写的还行,请点个 star 支持一下吧
欢迎前来交流探讨: 企鹅群568015492
目录
准备工作
gdi+需要有一点了解,不知道的可以百度瞅瞅
开始
添加一个用户控件,命名ucswitch
添加一个枚举用以控制样式
1 public enum switchtype 2 { 3 /// <summary> 4 /// 椭圆 5 /// </summary> 6 ellipse, 7 /// <summary> 8 /// 四边形 9 /// </summary> 10 quadrilateral, 11 /// <summary> 12 /// 横线 13 /// </summary> 14 line 15 }
添加属性
1 [description("选中改变事件"), category("自定义")] 2 public event eventhandler checkedchanged; 3 private color m_truecolor = color.fromargb(34, 163, 169); 4 5 [description("选中时颜色"), category("自定义")] 6 public color truecolor 7 { 8 get { return m_truecolor; } 9 set 10 { 11 m_truecolor = value; 12 refresh(); 13 } 14 } 15 16 private color m_falsecolor = color.fromargb(111, 122, 126); 17 18 [description("没有选中时颜色"), category("自定义")] 19 public color falsecolor 20 { 21 get { return m_falsecolor; } 22 set 23 { 24 m_falsecolor = value; 25 refresh(); 26 } 27 } 28 29 private bool m_checked; 30 31 [description("是否选中"), category("自定义")] 32 public bool checked 33 { 34 get { return m_checked; } 35 set 36 { 37 m_checked = value; 38 refresh(); 39 if (checkedchanged != null) 40 { 41 checkedchanged(this, null); 42 } 43 } 44 } 45 46 private string[] m_texts; 47 48 [description("文本值,当选中或没有选中时显示,必须是长度为2的数组"), category("自定义")] 49 public string[] texts 50 { 51 get { return m_texts; } 52 set 53 { 54 m_texts = value; 55 refresh(); 56 } 57 } 58 private switchtype m_switchtype = switchtype.ellipse; 59 60 [description("显示类型"), category("自定义")] 61 public switchtype switchtype 62 { 63 get { return m_switchtype; } 64 set 65 { 66 m_switchtype = value; 67 refresh(); 68 } 69 } 70 71 public override font font 72 { 73 get 74 { 75 return base.font; 76 } 77 set 78 { 79 base.font = value; 80 refresh(); 81 } 82 }
重绘
1 protected override void onpaint(painteventargs e) 2 { 3 base.onpaint(e); 4 var g = e.graphics; 5 g.setgdihigh(); 6 if (m_switchtype == hzh_controls.controls.switchtype.ellipse) 7 { 8 var fillcolor = m_checked ? m_truecolor : m_falsecolor; 9 graphicspath path = new graphicspath(); 10 path.addline(new point(this.height / 2, 1), new point(this.width - this.height / 2, 1)); 11 path.addarc(new rectangle(this.width - this.height - 1, 1, this.height - 2, this.height - 2), -90, 180); 12 path.addline(new point(this.width - this.height / 2, this.height - 1), new point(this.height / 2, this.height - 1)); 13 path.addarc(new rectangle(1, 1, this.height - 2, this.height - 2), 90, 180); 14 g.fillpath(new solidbrush(fillcolor), path); 15 16 string strtext = string.empty; 17 if (m_texts != null && m_texts.length == 2) 18 { 19 if (m_checked) 20 { 21 strtext = m_texts[0]; 22 } 23 else 24 { 25 strtext = m_texts[1]; 26 } 27 } 28 29 if (m_checked) 30 { 31 g.fillellipse(brushes.white, new rectangle(this.width - this.height - 1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 32 if (string.isnullorempty(strtext)) 33 { 34 g.drawellipse(new pen(color.white, 2), new rectangle((this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 35 } 36 else 37 { 38 system.drawing.sizef sizef = g.measurestring(strtext.replace(" ", "a"), font); 39 int inttexty = (this.height - (int)sizef.height) / 2 + 2; 40 g.drawstring(strtext, font, brushes.white, new point((this.height - 2 - 4) / 2, inttexty)); 41 } 42 } 43 else 44 { 45 g.fillellipse(brushes.white, new rectangle(1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 46 if (string.isnullorempty(strtext)) 47 { 48 g.drawellipse(new pen(color.white, 2), new rectangle(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 49 } 50 else 51 { 52 system.drawing.sizef sizef = g.measurestring(strtext.replace(" ", "a"), font); 53 int inttexty = (this.height - (int)sizef.height) / 2 + 2; 54 g.drawstring(strtext, font, brushes.white, new point(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2 - (int)sizef.width / 2, inttexty)); 55 } 56 } 57 } 58 else if (m_switchtype == hzh_controls.controls.switchtype.quadrilateral) 59 { 60 var fillcolor = m_checked ? m_truecolor : m_falsecolor; 61 graphicspath path = new graphicspath(); 62 int intradius = 5; 63 path.addarc(0, 0, intradius, intradius, 180f, 90f); 64 path.addarc(this.width - intradius - 1, 0, intradius, intradius, 270f, 90f); 65 path.addarc(this.width - intradius - 1, this.height - intradius - 1, intradius, intradius, 0f, 90f); 66 path.addarc(0, this.height - intradius - 1, intradius, intradius, 90f, 90f); 67 68 g.fillpath(new solidbrush(fillcolor), path); 69 70 string strtext = string.empty; 71 if (m_texts != null && m_texts.length == 2) 72 { 73 if (m_checked) 74 { 75 strtext = m_texts[0]; 76 } 77 else 78 { 79 strtext = m_texts[1]; 80 } 81 } 82 83 if (m_checked) 84 { 85 graphicspath path2 = new graphicspath(); 86 path2.addarc(this.width - this.height - 1 + 2, 1 + 2, intradius, intradius, 180f, 90f); 87 path2.addarc(this.width - 1 - 2 - intradius, 1 + 2, intradius, intradius, 270f, 90f); 88 path2.addarc(this.width - 1 - 2 - intradius, this.height - 2 - intradius - 1, intradius, intradius, 0f, 90f); 89 path2.addarc(this.width - this.height - 1 + 2, this.height - 2 - intradius - 1, intradius, intradius, 90f, 90f); 90 g.fillpath(brushes.white, path2); 91 92 if (string.isnullorempty(strtext)) 93 { 94 g.drawellipse(new pen(color.white, 2), new rectangle((this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 95 } 96 else 97 { 98 system.drawing.sizef sizef = g.measurestring(strtext.replace(" ", "a"), font); 99 int inttexty = (this.height - (int)sizef.height) / 2 + 2; 100 g.drawstring(strtext, font, brushes.white, new point((this.height - 2 - 4) / 2, inttexty)); 101 } 102 } 103 else 104 { 105 graphicspath path2 = new graphicspath(); 106 path2.addarc(1 + 2, 1 + 2, intradius, intradius, 180f, 90f); 107 path2.addarc(this.height - 2 - intradius, 1 + 2, intradius, intradius, 270f, 90f); 108 path2.addarc(this.height - 2 - intradius, this.height - 2 - intradius - 1, intradius, intradius, 0f, 90f); 109 path2.addarc(1 + 2, this.height - 2 - intradius - 1, intradius, intradius, 90f, 90f); 110 g.fillpath(brushes.white, path2); 111 112 //g.fillellipse(brushes.white, new rectangle(1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 113 if (string.isnullorempty(strtext)) 114 { 115 g.drawellipse(new pen(color.white, 2), new rectangle(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 116 } 117 else 118 { 119 system.drawing.sizef sizef = g.measurestring(strtext.replace(" ", "a"), font); 120 int inttexty = (this.height - (int)sizef.height) / 2 + 2; 121 g.drawstring(strtext, font, brushes.white, new point(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2 - (int)sizef.width / 2, inttexty)); 122 } 123 } 124 } 125 else 126 { 127 var fillcolor = m_checked ? m_truecolor : m_falsecolor; 128 int intlineheight = (this.height - 2 - 4) / 2; 129 130 graphicspath path = new graphicspath(); 131 path.addline(new point(this.height / 2, (this.height - intlineheight) / 2), new point(this.width - this.height / 2, (this.height - intlineheight) / 2)); 132 path.addarc(new rectangle(this.width - this.height / 2 - intlineheight - 1, (this.height - intlineheight) / 2, intlineheight, intlineheight), -90, 180); 133 path.addline(new point(this.width - this.height / 2, (this.height - intlineheight) / 2 + intlineheight), new point(this.width - this.height / 2, (this.height - intlineheight) / 2 + intlineheight)); 134 path.addarc(new rectangle(this.height / 2, (this.height - intlineheight) / 2, intlineheight, intlineheight), 90, 180); 135 g.fillpath(new solidbrush(fillcolor), path); 136 137 if (m_checked) 138 { 139 g.fillellipse(new solidbrush(fillcolor), new rectangle(this.width - this.height - 1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 140 g.fillellipse(brushes.white, new rectangle(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2 - 4, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 141 } 142 else 143 { 144 g.fillellipse(new solidbrush(fillcolor), new rectangle(1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 145 g.fillellipse(brushes.white, new rectangle((this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2 + 4, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 146 } 147 } 148 }
处理一下点击事件
1 void ucswitch_mousedown(object sender, mouseeventargs e) 2 { 3 checked = !checked; 4 }
完整代码
1 using system; 2 using system.collections.generic; 3 using system.componentmodel; 4 using system.drawing; 5 using system.data; 6 using system.linq; 7 using system.text; 8 using system.windows.forms; 9 using system.drawing.drawing2d; 10 11 namespace hzh_controls.controls 12 { 13 [defaultevent("checkedchanged")] 14 public partial class ucswitch : usercontrol 15 { 16 [description("选中改变事件"), category("自定义")] 17 public event eventhandler checkedchanged; 18 private color m_truecolor = color.fromargb(34, 163, 169); 19 20 [description("选中时颜色"), category("自定义")] 21 public color truecolor 22 { 23 get { return m_truecolor; } 24 set 25 { 26 m_truecolor = value; 27 refresh(); 28 } 29 } 30 31 private color m_falsecolor = color.fromargb(111, 122, 126); 32 33 [description("没有选中时颜色"), category("自定义")] 34 public color falsecolor 35 { 36 get { return m_falsecolor; } 37 set 38 { 39 m_falsecolor = value; 40 refresh(); 41 } 42 } 43 44 private bool m_checked; 45 46 [description("是否选中"), category("自定义")] 47 public bool checked 48 { 49 get { return m_checked; } 50 set 51 { 52 m_checked = value; 53 refresh(); 54 if (checkedchanged != null) 55 { 56 checkedchanged(this, null); 57 } 58 } 59 } 60 61 private string[] m_texts; 62 63 [description("文本值,当选中或没有选中时显示,必须是长度为2的数组"), category("自定义")] 64 public string[] texts 65 { 66 get { return m_texts; } 67 set 68 { 69 m_texts = value; 70 refresh(); 71 } 72 } 73 private switchtype m_switchtype = switchtype.ellipse; 74 75 [description("显示类型"), category("自定义")] 76 public switchtype switchtype 77 { 78 get { return m_switchtype; } 79 set 80 { 81 m_switchtype = value; 82 refresh(); 83 } 84 } 85 86 public override font font 87 { 88 get 89 { 90 return base.font; 91 } 92 set 93 { 94 base.font = value; 95 refresh(); 96 } 97 } 98 99 100 public ucswitch() 101 { 102 initializecomponent(); 103 this.setstyle(controlstyles.allpaintinginwmpaint, true); 104 this.setstyle(controlstyles.doublebuffer, true); 105 this.setstyle(controlstyles.resizeredraw, true); 106 this.setstyle(controlstyles.selectable, true); 107 this.setstyle(controlstyles.supportstransparentbackcolor, true); 108 this.setstyle(controlstyles.userpaint, true); 109 this.mousedown += ucswitch_mousedown; 110 } 111 112 void ucswitch_mousedown(object sender, mouseeventargs e) 113 { 114 checked = !checked; 115 } 116 117 protected override void onpaint(painteventargs e) 118 { 119 base.onpaint(e); 120 var g = e.graphics; 121 g.setgdihigh(); 122 if (m_switchtype == hzh_controls.controls.switchtype.ellipse) 123 { 124 var fillcolor = m_checked ? m_truecolor : m_falsecolor; 125 graphicspath path = new graphicspath(); 126 path.addline(new point(this.height / 2, 1), new point(this.width - this.height / 2, 1)); 127 path.addarc(new rectangle(this.width - this.height - 1, 1, this.height - 2, this.height - 2), -90, 180); 128 path.addline(new point(this.width - this.height / 2, this.height - 1), new point(this.height / 2, this.height - 1)); 129 path.addarc(new rectangle(1, 1, this.height - 2, this.height - 2), 90, 180); 130 g.fillpath(new solidbrush(fillcolor), path); 131 132 string strtext = string.empty; 133 if (m_texts != null && m_texts.length == 2) 134 { 135 if (m_checked) 136 { 137 strtext = m_texts[0]; 138 } 139 else 140 { 141 strtext = m_texts[1]; 142 } 143 } 144 145 if (m_checked) 146 { 147 g.fillellipse(brushes.white, new rectangle(this.width - this.height - 1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 148 if (string.isnullorempty(strtext)) 149 { 150 g.drawellipse(new pen(color.white, 2), new rectangle((this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 151 } 152 else 153 { 154 system.drawing.sizef sizef = g.measurestring(strtext.replace(" ", "a"), font); 155 int inttexty = (this.height - (int)sizef.height) / 2 + 2; 156 g.drawstring(strtext, font, brushes.white, new point((this.height - 2 - 4) / 2, inttexty)); 157 } 158 } 159 else 160 { 161 g.fillellipse(brushes.white, new rectangle(1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 162 if (string.isnullorempty(strtext)) 163 { 164 g.drawellipse(new pen(color.white, 2), new rectangle(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 165 } 166 else 167 { 168 system.drawing.sizef sizef = g.measurestring(strtext.replace(" ", "a"), font); 169 int inttexty = (this.height - (int)sizef.height) / 2 + 2; 170 g.drawstring(strtext, font, brushes.white, new point(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2 - (int)sizef.width / 2, inttexty)); 171 } 172 } 173 } 174 else if (m_switchtype == hzh_controls.controls.switchtype.quadrilateral) 175 { 176 var fillcolor = m_checked ? m_truecolor : m_falsecolor; 177 graphicspath path = new graphicspath(); 178 int intradius = 5; 179 path.addarc(0, 0, intradius, intradius, 180f, 90f); 180 path.addarc(this.width - intradius - 1, 0, intradius, intradius, 270f, 90f); 181 path.addarc(this.width - intradius - 1, this.height - intradius - 1, intradius, intradius, 0f, 90f); 182 path.addarc(0, this.height - intradius - 1, intradius, intradius, 90f, 90f); 183 184 g.fillpath(new solidbrush(fillcolor), path); 185 186 string strtext = string.empty; 187 if (m_texts != null && m_texts.length == 2) 188 { 189 if (m_checked) 190 { 191 strtext = m_texts[0]; 192 } 193 else 194 { 195 strtext = m_texts[1]; 196 } 197 } 198 199 if (m_checked) 200 { 201 graphicspath path2 = new graphicspath(); 202 path2.addarc(this.width - this.height - 1 + 2, 1 + 2, intradius, intradius, 180f, 90f); 203 path2.addarc(this.width - 1 - 2 - intradius, 1 + 2, intradius, intradius, 270f, 90f); 204 path2.addarc(this.width - 1 - 2 - intradius, this.height - 2 - intradius - 1, intradius, intradius, 0f, 90f); 205 path2.addarc(this.width - this.height - 1 + 2, this.height - 2 - intradius - 1, intradius, intradius, 90f, 90f); 206 g.fillpath(brushes.white, path2); 207 208 if (string.isnullorempty(strtext)) 209 { 210 g.drawellipse(new pen(color.white, 2), new rectangle((this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 211 } 212 else 213 { 214 system.drawing.sizef sizef = g.measurestring(strtext.replace(" ", "a"), font); 215 int inttexty = (this.height - (int)sizef.height) / 2 + 2; 216 g.drawstring(strtext, font, brushes.white, new point((this.height - 2 - 4) / 2, inttexty)); 217 } 218 } 219 else 220 { 221 graphicspath path2 = new graphicspath(); 222 path2.addarc(1 + 2, 1 + 2, intradius, intradius, 180f, 90f); 223 path2.addarc(this.height - 2 - intradius, 1 + 2, intradius, intradius, 270f, 90f); 224 path2.addarc(this.height - 2 - intradius, this.height - 2 - intradius - 1, intradius, intradius, 0f, 90f); 225 path2.addarc(1 + 2, this.height - 2 - intradius - 1, intradius, intradius, 90f, 90f); 226 g.fillpath(brushes.white, path2); 227 228 //g.fillellipse(brushes.white, new rectangle(1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 229 if (string.isnullorempty(strtext)) 230 { 231 g.drawellipse(new pen(color.white, 2), new rectangle(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 232 } 233 else 234 { 235 system.drawing.sizef sizef = g.measurestring(strtext.replace(" ", "a"), font); 236 int inttexty = (this.height - (int)sizef.height) / 2 + 2; 237 g.drawstring(strtext, font, brushes.white, new point(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2 - (int)sizef.width / 2, inttexty)); 238 } 239 } 240 } 241 else 242 { 243 var fillcolor = m_checked ? m_truecolor : m_falsecolor; 244 int intlineheight = (this.height - 2 - 4) / 2; 245 246 graphicspath path = new graphicspath(); 247 path.addline(new point(this.height / 2, (this.height - intlineheight) / 2), new point(this.width - this.height / 2, (this.height - intlineheight) / 2)); 248 path.addarc(new rectangle(this.width - this.height / 2 - intlineheight - 1, (this.height - intlineheight) / 2, intlineheight, intlineheight), -90, 180); 249 path.addline(new point(this.width - this.height / 2, (this.height - intlineheight) / 2 + intlineheight), new point(this.width - this.height / 2, (this.height - intlineheight) / 2 + intlineheight)); 250 path.addarc(new rectangle(this.height / 2, (this.height - intlineheight) / 2, intlineheight, intlineheight), 90, 180); 251 g.fillpath(new solidbrush(fillcolor), path); 252 253 if (m_checked) 254 { 255 g.fillellipse(new solidbrush(fillcolor), new rectangle(this.width - this.height - 1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 256 g.fillellipse(brushes.white, new rectangle(this.width - 2 - (this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2 - 4, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 257 } 258 else 259 { 260 g.fillellipse(new solidbrush(fillcolor), new rectangle(1 + 2, 1 + 2, this.height - 2 - 4, this.height - 2 - 4)); 261 g.fillellipse(brushes.white, new rectangle((this.height - 2 - 4) / 2 - ((this.height - 2 - 4) / 2) / 2 + 4, (this.height - 2 - (this.height - 2 - 4) / 2) / 2 + 1, (this.height - 2 - 4) / 2, (this.height - 2 - 4) / 2)); 262 } 263 } 264 } 265 266 } 267 268 public enum switchtype 269 { 270 /// <summary> 271 /// 椭圆 272 /// </summary> 273 ellipse, 274 /// <summary> 275 /// 四边形 276 /// </summary> 277 quadrilateral, 278 /// <summary> 279 /// 横线 280 /// </summary> 281 line 282 } 283 }
1 namespace hzh_controls.controls 2 { 3 partial class ucswitch 4 { 5 /// <summary> 6 /// 必需的设计器变量。 7 /// </summary> 8 private system.componentmodel.icontainer components = null; 9 10 /// <summary> 11 /// 清理所有正在使用的资源。 12 /// </summary> 13 /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> 14 protected override void dispose(bool disposing) 15 { 16 if (disposing && (components != null)) 17 { 18 components.dispose(); 19 } 20 base.dispose(disposing); 21 } 22 23 #region 组件设计器生成的代码 24 25 /// <summary> 26 /// 设计器支持所需的方法 - 不要 27 /// 使用代码编辑器修改此方法的内容。 28 /// </summary> 29 private void initializecomponent() 30 { 31 this.suspendlayout(); 32 // 33 // ucswitch 34 // 35 this.autoscalemode = system.windows.forms.autoscalemode.none; 36 this.backcolor = system.drawing.color.transparent; 37 this.name = "ucswitch"; 38 this.size = new system.drawing.size(83, 31); 39 this.resumelayout(false); 40 41 } 42 43 #endregion 44 } 45 }
用处及效果
最后的话
如果你喜欢的话,请到 点个星 星吧