-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
475 lines (237 loc) · 393 KB
/
atom.xml
File metadata and controls
475 lines (237 loc) · 393 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Admibrill</title>
<subtitle>Run the code, run after the code</subtitle>
<link href="https://blog.qyadbr.top/atom.xml" rel="self"/>
<link href="https://blog.qyadbr.top/"/>
<updated>2025-08-30T07:38:59.299Z</updated>
<id>https://blog.qyadbr.top/</id>
<author>
<name>Admibrill</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>博客一周年记</title>
<link href="https://blog.qyadbr.top/posts/hexo17/"/>
<id>https://blog.qyadbr.top/posts/hexo17/</id>
<published>2025-08-30T06:17:00.000Z</published>
<updated>2025-08-30T07:38:59.299Z</updated>
<content type="html"><![CDATA[<p>不知不觉间,Admibrill已经在博客圈待了一个春秋了呢。<br>很久没有发博客了,那现在发一篇吧</p><h2 id="小站的建立"><a href="#小站的建立" class="headerlink" title="小站的建立"></a>小站的建立</h2><p>建站的时候也遇到了许多困难呢,不过好在一一解决了<br>买了域名,<del>这样就能加友链了</del><br>后来主题迁移到了Solitude!博客变快了好多呢</p><h2 id="GH-Orgs"><a href="#GH-Orgs" class="headerlink" title="GH Orgs"></a>GH Orgs</h2><p>这一年Admibrill加入了很多org呢</p><ul><li><a href="https://github.com/LingmoOS">LingmoOS</a></li><li><a href="https://github.com/ITCraftDevelopmentTeam">ITCDT</a></li><li>相侵想碍异家人</li><li>LiteYuki</li><li>….(<del>还有等等</del>)<h2 id="项目"><a href="#项目" class="headerlink" title="项目"></a>项目</h2></li></ul><h3 id="已Archive"><a href="#已Archive" class="headerlink" title="已Archive"></a>已Archive</h3><p>好奇怪为什么之前要用这么多时间搞这些呢<br>也许是用来熟悉Qt的吧</p><ul><li>LingmoPyUI(已被LingmoUIPy取代)</li><li>lingmo-webbrowser(还是用firefox好不折腾了)<h3 id="Under-Development"><a href="#Under-Development" class="headerlink" title="Under Development"></a>Under Development</h3></li><li><a href="https://github.com/Uniquenium">Uniquenium</a>(桌面小组件及桌面自定义工具)</li><li>AdmiBlog(准备迁移到Next.js的博客)<h2 id="是Qt!"><a href="#是Qt!" class="headerlink" title="是Qt!"></a>是Qt!</h2>自从加入LingmoOS,Admibrill开始研究Qt<br>最常访问的页面:<a href="https://doc.qt.io/qt-6/qmltypes.html">All QML Types | Qt 6.9</a><br>Uniquenium刚开始是用Python写的,让还发现了各种问题<br>于是迁移C++ Qt<br>于是开始经常访问的页面:<a href="https://doc.qt.io/qt-6/classes.html">All C++ Classes | Qt 6.9</a><br>但是Python也有许多好的特性<br>为了用这些Admibrill又开始折腾<a href="https://pybind11.readthedocs.io/en/stable/">pybind11 documentation</a></li></ul><h2 id="新名字!"><a href="#新名字!" class="headerlink" title="新名字!"></a>新名字!</h2><p>钦烨这个名字是瞎编的。Admibrill这个英文名是直接意译+省略拼出来的<br>后来觉得钦烨两个字不好于是起了个新名字——埃氮幂!</p><h2 id="接下来要折腾什么?"><a href="#接下来要折腾什么?" class="headerlink" title="接下来要折腾什么?"></a>接下来要折腾什么?</h2><p>由于Admibrill即将踏入九年级的大门,这个空余时间会变少(真的很少!)<br>但是Admibrill希望可以研究这些东西:</p><ul><li>Next.js(including HTML CSS JS React)</li><li>Vue.js</li><li>Vite.js</li><li>Tauri</li><li>….(<del>没错还有等等</del>)</li></ul><p>这一年我<del>竟自己编出来了</del>一句话,那就以这句话结尾吧<br>Run the code,run after the code!</p>]]></content>
<summary type="html"><p>不知不觉间,Admibrill已经在博客圈待了一个春秋了呢。<br>很久没有发博客了,那现在发一篇吧</p>
<h2 id="小站的建立"><a href="#小站的建立" class="headerlink" title="小站的建立"></a>小站的建立</h2><p>建站的时候也遇到了许多困难呢,不过好在一一解决了<br>买了域名,<del>这样就能加友链了</del><br>后来主题</summary>
<category term="周年记" scheme="https://blog.qyadbr.top/categories/%E5%91%A8%E5%B9%B4%E8%AE%B0/"/>
<category term="日常记录" scheme="https://blog.qyadbr.top/tags/%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95/"/>
</entry>
<entry>
<title>P13020 [GESP202506 八级] 遍历计数 题解</title>
<link href="https://blog.qyadbr.top/posts/hexo16/"/>
<id>https://blog.qyadbr.top/posts/hexo16/</id>
<published>2025-06-30T11:18:06.000Z</published>
<updated>2025-06-30T11:45:28.003Z</updated>
<content type="html"><![CDATA[<h1 id="原题"><a href="#原题" class="headerlink" title="原题"></a>原题</h1><h2 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h2><p>给定一棵有 $n$ 个结点的树 $T$,结点依次以 $1,2,\dots,n$ 标号。树 $T$ 的深度优先遍历序可由以下过程得到:</p><ol><li>选定深度优先遍历的起点 $s$($1 \leq s \leq n$),当前位置结点即是起点。</li><li>若当前结点存在未被遍历的相邻结点 $u$ 则遍历 $u$,也即令当前位置结点为 $u$ 并重复这一步;否则回溯。</li><li>按照遍历结点的顺序依次写下结点编号,即可得到一组深度优先遍历序。</li></ol><p>第一步中起点的选择是任意的,并且第二步中遍历相邻结点的顺序也是任意的,因此对于同一棵树 $T$ 可能有多组不同的深度优先遍历序。请你求出树 $T$ 有多少组不同的深度优先遍历序。由于答案可能很大,你只需要求出答案对 $10^9$ 取模之后的结果。</p><h2 id="输入格式"><a href="#输入格式" class="headerlink" title="输入格式"></a>输入格式</h2><p>第一行,一个整数 $n$,表示树 $T$ 的结点数。</p><p>接下来 $n-1$ 行,每行两个正整数 $u_i, v_i$,表示树 $T$ 中的一条连接结点 $u_i, v_i$ 的边。</p><h2 id="输出格式"><a href="#输出格式" class="headerlink" title="输出格式"></a>输出格式</h2><p>输出一行,一个整数,表示树 $T$ 的不同的深度优先遍历序数量对 $10^9$ 取模的结果。</p><h2 id="输入输出样例-1"><a href="#输入输出样例-1" class="headerlink" title="输入输出样例 #1"></a>输入输出样例 #1</h2><h3 id="输入-1"><a href="#输入-1" class="headerlink" title="输入 #1"></a>输入 #1</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">4</span><br><span class="line">1 2</span><br><span class="line">2 3</span><br><span class="line">3 4</span><br></pre></td></tr></table></figure><h3 id="输出-1"><a href="#输出-1" class="headerlink" title="输出 #1"></a>输出 #1</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">6</span><br></pre></td></tr></table></figure><h2 id="输入输出样例-2"><a href="#输入输出样例-2" class="headerlink" title="输入输出样例 #2"></a>输入输出样例 #2</h2><h3 id="输入-2"><a href="#输入-2" class="headerlink" title="输入 #2"></a>输入 #2</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">8</span><br><span class="line">1 2</span><br><span class="line">1 3</span><br><span class="line">1 4</span><br><span class="line">2 5</span><br><span class="line">2 6</span><br><span class="line">3 7</span><br><span class="line">3 8</span><br></pre></td></tr></table></figure><h3 id="输出-2"><a href="#输出-2" class="headerlink" title="输出 #2"></a>输出 #2</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">112</span><br></pre></td></tr></table></figure><h2 id="说明-提示"><a href="#说明-提示" class="headerlink" title="说明/提示"></a>说明/提示</h2><p>对于 40% 的测试点,保证 $1 \leq n \leq 8$。</p><p>对于另外 20% 的测试点,保证给定的树是一条链。</p><p>对于所有测试点,保证 $1 \leq n \leq 10^5$。</p><h1 id="解"><a href="#解" class="headerlink" title="解"></a>解</h1><p>题目表面上说是多少种深搜的序列,实际上深搜不是重点,重点是求排列数。</p><p><strong>40分代码</strong></p><p>对于每一个节点,假设它有 $n$ 个子节点,那么可以选择的,抛开子节点的子节点不看,遍历方法就有 $A_n^n$ 即 $n!$ 种。</p><p>因此,总的方案数就是所有的节点的子节点数阶乘的总乘积。</p><p>时间复杂度 $O(n^2)$ 。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="type">int</span> n,u,v,ans,sum;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> N=<span class="number">1e5</span><span class="number">+5</span>;</span><br><span class="line">vector<<span class="type">int</span>>g[N];<span class="comment">//邻接表方便求连边数</span></span><br><span class="line"><span class="type">int</span> f[N];</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> mod=<span class="number">1e9</span>;</span><br><span class="line"><span class="type">bool</span> vis[N];</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">dfs</span><span class="params">(<span class="type">int</span> x,<span class="type">int</span> fa)</span></span>{</span><br><span class="line"> <span class="comment">//如果是起始节点,子节点数就是连边数,否则要减去和父节点相连的一条边</span></span><br><span class="line"> ans=(ans*f[(fa==<span class="number">-1</span>?g[x].<span class="built_in">size</span>():g[x].<span class="built_in">size</span>()<span class="number">-1</span>)])%mod;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">auto</span> i:g[x]){</span><br><span class="line"> <span class="keyword">if</span>(!vis[i]){</span><br><span class="line"> vis[i]=<span class="number">1</span>;</span><br><span class="line"> <span class="built_in">dfs</span>(i,x);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"> cin>>n;</span><br><span class="line"> f[<span class="number">0</span>]=<span class="number">1</span>;</span><br><span class="line"> <span class="comment">//预处理阶乘数</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> f[i]=(f[i<span class="number">-1</span>]*i)%mod;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<n;i++){</span><br><span class="line"> cin>>u>>v;</span><br><span class="line"> g[u].<span class="built_in">push_back</span>(v);</span><br><span class="line"> g[v].<span class="built_in">push_back</span>(u);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//每一个节点都可能是起始节点</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> <span class="built_in">memset</span>(vis,<span class="number">0</span>,<span class="built_in">sizeof</span>(vis));</span><br><span class="line"> vis[i]=<span class="number">1</span>;</span><br><span class="line"> ans=<span class="number">1</span>;</span><br><span class="line"> <span class="built_in">dfs</span>(i,<span class="number">-1</span>);</span><br><span class="line"> sum=(sum+ans)%mod;</span><br><span class="line"> }</span><br><span class="line"> cout<<sum;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>60分代码</strong></p><p>观察每次的乘积可知,每次所有的子节点都乘以相同的因数(连边数-1),所以可以一次性算出来,由于起始节点要乘 $n!$ 而不是 $(n-1)!$ ,所以再乘 $n$ 即可。<br>时间复杂度 $O(n)$ 。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> int long long</span></span><br><span class="line"><span class="type">int</span> n,u,v,mul=<span class="number">1</span>,sum;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> N=<span class="number">1e5</span><span class="number">+5</span>;</span><br><span class="line">vector<<span class="type">int</span>>g[N];</span><br><span class="line"><span class="type">int</span> f[N];</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> mod=<span class="number">1e9</span>;</span><br><span class="line"><span class="type">bool</span> vis[N];</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">dfs</span><span class="params">(<span class="type">int</span> x)</span></span>{</span><br><span class="line"> mul=(mul*f[g[x].<span class="built_in">size</span>()<span class="number">-1</span>])%mod;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">auto</span> i:g[x]){</span><br><span class="line"> <span class="keyword">if</span>(!vis[i]){</span><br><span class="line"> vis[i]=<span class="number">1</span>;</span><br><span class="line"> <span class="built_in">dfs</span>(i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">signed</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"> cin>>n;</span><br><span class="line"> f[<span class="number">0</span>]=<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> f[i]=(f[i<span class="number">-1</span>]*i)%mod;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<n;i++){</span><br><span class="line"> cin>>u>>v;</span><br><span class="line"> g[u].<span class="built_in">push_back</span>(v);</span><br><span class="line"> g[v].<span class="built_in">push_back</span>(u);</span><br><span class="line"> }</span><br><span class="line"> vis[<span class="number">1</span>]=<span class="number">1</span>;</span><br><span class="line"> <span class="built_in">dfs</span>(<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> <span class="type">int</span> res=(mul*g[i].<span class="built_in">size</span>())%mod;</span><br><span class="line"> sum=(sum+res)%mod;</span><br><span class="line"> }</span><br><span class="line"> cout<<sum;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>AC代码</strong></p><p>考虑特殊情况,当 $n=1$ 时,由于这个节点没有子节点所以连边数减 $1$ 会得到 $0$ ,造成 <code>mul</code> 得到 $0$。<br>所以再加一个特判得全分。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> int long long</span></span><br><span class="line"><span class="type">int</span> n,u,v,mul=<span class="number">1</span>,sum;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> N=<span class="number">1e5</span><span class="number">+5</span>;</span><br><span class="line">vector<<span class="type">int</span>>g[N];</span><br><span class="line"><span class="type">int</span> f[N];</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> mod=<span class="number">1e9</span>;</span><br><span class="line"><span class="type">bool</span> vis[N];</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">dfs</span><span class="params">(<span class="type">int</span> x)</span></span>{</span><br><span class="line"> mul=(mul*f[g[x].<span class="built_in">size</span>()<span class="number">-1</span>])%mod;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">auto</span> i:g[x]){</span><br><span class="line"> <span class="keyword">if</span>(!vis[i]){</span><br><span class="line"> vis[i]=<span class="number">1</span>;</span><br><span class="line"> <span class="built_in">dfs</span>(i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="type">signed</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"> cin>>n;</span><br><span class="line"> f[<span class="number">0</span>]=<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> f[i]=(f[i<span class="number">-1</span>]*i)%mod;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<n;i++){</span><br><span class="line"> cin>>u>>v;</span><br><span class="line"> g[u].<span class="built_in">push_back</span>(v);</span><br><span class="line"> g[v].<span class="built_in">push_back</span>(u);</span><br><span class="line"> }</span><br><span class="line"> vis[<span class="number">1</span>]=<span class="number">1</span>;</span><br><span class="line"> <span class="built_in">dfs</span>(<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> <span class="type">int</span> res=(mul*g[i].<span class="built_in">size</span>())%mod;</span><br><span class="line"> sum=(sum+res)%mod;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(n==<span class="number">1</span>)cout<<<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> cout<<sum;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>]]></content>
<summary type="html"><h1 id="原题"><a href="#原题" class="headerlink" title="原题"></a>原题</h1><h2 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h2><p>给定一棵有 $n$ 个结点的树 $T$,结点依次以 $1,2,\dots,n$ 标号。树 $T$ 的深度优先遍</summary>
<category term="题解" scheme="https://blog.qyadbr.top/categories/%E9%A2%98%E8%A7%A3/"/>
<category term="题解" scheme="https://blog.qyadbr.top/tags/%E9%A2%98%E8%A7%A3/"/>
</entry>
<entry>
<title>Moonlark(Nonebot2+Python)命令式聊天机器人插件开发记录</title>
<link href="https://blog.qyadbr.top/posts/hexo15/"/>
<id>https://blog.qyadbr.top/posts/hexo15/</id>
<published>2025-05-25T13:58:06.000Z</published>
<updated>2025-05-28T14:01:14.036Z</updated>
<content type="html"><后,我开始想去给由Python+Nonebot2写出来的<a href="https://github.com/Moonlark-Dev/Moonlark">Moonlark</a>做一些贡献。</p><h1 id="参考的资料"><a href="#参考的资料" class="headerlink" title="参考的资料"></a>参考的资料</h1><a class="tag-link" href="https://nonebot.dev/" target="_blank"> <div class="tag-link-tips">引用站外链接</div> <div class="tag-link-bottom"> <div class="tag-link-left"> <i class="solitude fas fa-link"></i> </div> <div class="tag-link-right"> <div class="tag-link-title">Nonebot</div> <div class="tag-link-sitename">https://nonebot.dev/</div> </div> <i class="solitude fas fa-chevron-right"></i> </div></a><a class="tag-link" href="https://moonlark-docs.itcdt.top/" target="_blank"> <div class="tag-link-tips">引用站外链接</div> <div class="tag-link-bottom"> <div class="tag-link-left"> <i class="solitude fas fa-link"></i> </div> <div class="tag-link-right"> <div class="tag-link-title">Moonlark开发文档</div> <div class="tag-link-sitename">https://moonlark-docs.itcdt.top/</div> </div> <i class="solitude fas fa-chevron-right"></i> </div></a><h1 id="搭建开发环境"><a href="#搭建开发环境" class="headerlink" title="搭建开发环境"></a>搭建开发环境</h1><p>(基于moonlark文档修改)</p><ol><li>确保您的 Python 版本 <code>>= 3.11</code>。</li><li>安装包管理工具 <a href="https://python-poetry.org/docs/">Poetry</a>(建议安装 <code>2.1.0</code> 及以上的版本)。</li><li>克隆仓库并安装依赖,可以使用以下指令:</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/Moonlark-Dev/Moonlark</span><br><span class="line"><span class="built_in">cd</span> Moonlark</span><br><span class="line">pip install pipx</span><br><span class="line">pipx install nb-cli</span><br><span class="line">pipx install poetry</span><br><span class="line">poetry install</span><br></pre></td></tr></table></figure><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置<a href="https://moonlark-docs.itcdt.top/quick-start/create-develop-environment.html#%E9%85%8D%E7%BD%AE"></a></h2><p>将<code>.env.template</code> 复制为 <code>.env</code> 并在 <code>.env</code> 文件中填写相关环境变量。<br>(不测试对应的功能不用填)</p><h2 id="搭建测试环境"><a href="#搭建测试环境" class="headerlink" title="搭建测试环境"></a>搭建测试环境<a href="https://moonlark-docs.itcdt.top/quick-start/create-develop-environment.html#%E6%90%AD%E5%BB%BA%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83"></a></h2><p>为了测试 Moonlark 的代码,您需要运行一个 OneBot 实现并使其连接到 <code>ws://localhost:8080/onebot/v11/ws</code>(默认状态下),我们提供了以下两个参考方案:</p><ul><li>使用 <a href="https://napneko.github.io/guide/start-install">NapCat</a>: 需要有一个闲置的 QQ 号供 NapCat 登录。同时,您可能需要承担该账号被 TX 冻结的风险。</li><li>使用 <a href="https://github.com/A-kirami/matcha">Matcha</a>: 目前已知无法显示 Moonlark 发出的图片。</li></ul><p>NapCat确实好用,但是在qq上面,所有用了两天就被tx封。<br>Matcha虽然不能直接显示图片,但是在测试时可以通过nonebot的logger和with open(path,”wb”)将bytes类型的图片保存到本地。</p><h1 id="开发"><a href="#开发" class="headerlink" title="开发"></a>开发</h1><p>一个moonlark插件基本上要有这些内容<br>假设插件的名字叫<code>nonebot_plugin_[name]</code>。</p><h2 id="src-plugins-nonebot-plugin-name"><a href="#src-plugins-nonebot-plugin-name" class="headerlink" title="src/plugins/nonebot_plugin_[name]"></a><code>src/plugins/nonebot_plugin_[name]</code></h2><p>首先建立插件文件夹</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nb plugin create nonebot_plugin_[name]</span><br></pre></td></tr></table></figure><p>修改Moonlark目录下的<code>pyproject.toml</code><br><figure class="highlight toml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="section">[tool.nonebot]</span></span><br><span class="line">...</span><br><span class="line"><span class="attr">plugins</span>=[</span><br><span class="line">...,</span><br><span class="line"><span class="string">"nonebot_plugin_[name]"</span>,<span class="comment">#加入这一行,确保插件会被加载</span></span><br><span class="line">...</span><br><span class="line">]</span><br></pre></td></tr></table></figure></p><h2 id="src-plugins-nonebot-plugin-name-init-py"><a href="#src-plugins-nonebot-plugin-name-init-py" class="headerlink" title="src/plugins/nonebot_plugin_[name]/__init__.py"></a><code>src/plugins/nonebot_plugin_[name]/__init__.py</code></h2><p>这个文件包含了一些基本信息</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> nonebot <span class="keyword">import</span> require</span><br><span class="line"><span class="keyword">from</span> nonebot.plugin <span class="keyword">import</span> PluginMetadata</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> .config <span class="keyword">import</span> Config</span><br><span class="line"></span><br><span class="line">__plugin_meta__ = PluginMetadata(</span><br><span class="line"> name=<span class="string">"nonebot_plugin_[name]"</span>,</span><br><span class="line"> description=<span class="string">"描述"</span>,</span><br><span class="line"> usage=<span class="string">""</span>,</span><br><span class="line"> config=Config,</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">require(<span class="string">"nonebot_plugin_[othername]"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> . <span class="keyword">import</span> __main__</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="src-lang-lang-name-yaml"><a href="#src-lang-lang-name-yaml" class="headerlink" title="src/lang/[lang]/[name].yaml"></a><code>src/lang/[lang]/[name].yaml</code></h2><p>这是moonlark用于本地化(翻译)的文件<br>目前支持<code>zh_hans</code>(简体中文,大陆)、<code>zh_tw</code>(繁体中文,台湾)、<code>en_us</code>(英语,美国)三种语言。<br>每个语言文件夹下都要创建一个对应的yaml,才能识别成功,并且每个对应的yaml中的键都要相同<br>例如,在<code>zh_hans/[name].yaml</code>中有一个键<code>key</code>,那么在<code>zh_tw</code>和<code>en_us</code>下的<code>[name].yaml</code>都要有<code>key</code>这个键。</p><p>键的命名满足以下规则:</p><ul><li>不以数字开头;</li><li>由26个大写、26个小写、10个阿拉伯数字或者减号(<code>-</code>)组成</li><li>子键要缩进</li></ul><h2 id="src-templates-name-html-jinja"><a href="#src-templates-name-html-jinja" class="headerlink" title="src/templates/[name].html.jinja"></a><code>src/templates/[name].html.jinja</code></h2><p>有时候,机器人需要发送图片。这时需要一个图片模版来图片<br>引用Moonlark开发文档:</p><blockquote><h2 id="模板编写"><a href="#模板编写" class="headerlink" title="模板编写"></a>模板编写</h2><p>Render 读取的模板储存在 <code>src/templates</code> 中,后缀为 <code>*.jinja</code>。</p><p>一个模板的格式如下:</p><p>html</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">{% extends base %}</span><br><span class="line">{% block body %}</span><br><span class="line">{{ content }}</span><br><span class="line">{% endblock body %}</span><br></pre></td></tr></table></figure><h3 id="基模板"><a href="#基模板" class="headerlink" title="基模板"></a>基模板</h3><p>html</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{% extends base %}</span><br></pre></td></tr></table></figure><p>这里使用了一个模板变量 <code>base</code> 作为基模板的名称,这个变量在渲染时会自动填充为对应主题的基模板。</p><h3 id="内容块"><a href="#内容块" class="headerlink" title="内容块"></a>内容块</h3><h4 id="header"><a href="#header" class="headerlink" title="header"></a><code>header</code></h4><p>拓展页面页面的头部。</p><h4 id="body"><a href="#body" class="headerlink" title="body"></a><code>body</code></h4><p>卡片主体内容。</p><h4 id="card"><a href="#card" class="headerlink" title="card"></a><code>card</code></h4><p>卡片。</p><h3 id="保留变量"><a href="#保留变量" class="headerlink" title="保留变量"></a>保留变量</h3><p>这些变量会在渲染时被自动填充,请避免使用这些模板变量名。</p><ul><li><code>base</code>: 主题基模板的相对路径。</li><li><code>main_title</code>: 页面主标题。</li><li><code>footer</code>: 页面页脚(版权信息)。</li></ul><h2 id="主题"><a href="#主题" class="headerlink" title="主题"></a>主题<a href="https://moonlark-docs.itcdt.top/plugins/render.html#%E4%B8%BB%E9%A2%98"></a></h2><p>Render 支持主题,主题基模板储存在 <code>src/templates/base</code> 中,主题列表储存在 <code>src/plugins/nonebot_plugin_render/themes.json</code> 中。</p><h3 id="基模板"><a href="#基模板" class="headerlink" title="基模板"></a>基模板<a href="https://moonlark-docs.itcdt.top/plugins/render.html#%E5%9F%BA%E6%A8%A1%E6%9D%BF-1"></a></h3><p>一个主题的基模板需要定义以下变量和内容块:</p><h4 id="模板变量"><a href="#模板变量" class="headerlink" title="模板变量"></a>模板变量<a href="https://moonlark-docs.itcdt.top/plugins/render.html#%E6%A8%A1%E6%9D%BF%E5%8F%98%E9%87%8F"></a></h4><ul><li><code>main_title</code>: 页面主标题。</li><li><code>footer</code>: 页面页脚(版权信息)。</li></ul><h4 id="内容块"><a href="#内容块" class="headerlink" title="内容块"></a>内容块<a href="https://moonlark-docs.itcdt.top/plugins/render.html#%E5%86%85%E5%AE%B9%E5%9D%97-1"></a></h4><ul><li><code>header</code>: 页面拓展头部。</li><li><code>body</code>: 卡片主体内容。</li><li><code>card</code>: 卡片。</li></ul><p>TIP</p><p>一般来说,<code>card</code> 会覆盖 <code>body</code> 块。</p><h3 id="主题配置"><a href="#主题配置" class="headerlink" title="主题配置"></a>主题配置<a href="https://moonlark-docs.itcdt.top/plugins/render.html#%E4%B8%BB%E9%A2%98%E9%85%8D%E7%BD%AE"></a></h3><p>主题配置是一个 JSON 文件,格式为 <code>"主题ID": "主题模板相对于 src/templates 的路径"</code>。</p><h2 id="本地化"><a href="#本地化" class="headerlink" title="本地化"></a>本地化<a href="https://moonlark-docs.itcdt.top/plugins/render.html#%E6%9C%AC%E5%9C%B0%E5%8C%96"></a></h2><p>所有向用户展示的文本都要被本地化。</p><h2 id="本地文件引用"><a href="#本地文件引用" class="headerlink" title="本地文件引用"></a>本地文件引用<a href="https://moonlark-docs.itcdt.top/plugins/render.html#%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6%E5%BC%95%E7%94%A8"></a></h2><p>可以使用 <code>{% include "xx" %}</code> 块或 <code>src=xxx</code> 引入本地文件。 使用相对引入时,基路径为 <code>src/templates</code>。</p></blockquote><h2 id="src-plugins-nonebot-plugin-name-main-py"><a href="#src-plugins-nonebot-plugin-name-main-py" class="headerlink" title="src/plugins/nonebot_plugin_[name]/__main__.py"></a><code>src/plugins/nonebot_plugin_[name]/__main__.py</code></h2><p>一般nonebot的插件主要部分都是在这里写的<br>里面的内容由插件的功能而定,由开发者<del>自由发挥</del><br>但是有需要注意的几点:</p><h3 id="创建命令"><a href="#创建命令" class="headerlink" title="创建命令"></a>创建命令</h3><p>用户通过命令来使用nonebot2的插件。<br>Moonlark提供了一系列相关工具。(注意:这些都是nonebot2本身没有的)<br>首先在<code>__init__.py</code>里加上<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">require(<span class="string">"nonebot_plugin_alconna"</span>)</span><br><span class="line">require(<span class="string">"nonebot_plugin_larklang"</span>)</span><br><span class="line">require(<span class="string">"nonebot_plugin_larkuser"</span>)</span><br></pre></td></tr></table></figure><br>然后就可以在<code>__main__.py</code>里导入工具<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> nonebot_plugin_alconna <span class="keyword">import</span> Alconna, Args, on_alconna, Subcommand</span><br><span class="line"><span class="keyword">from</span> nonebot_plugin_larklang.__main__ <span class="keyword">import</span> LangHelper</span><br><span class="line"><span class="keyword">from</span> nonebot_plugin_larkuser.utils.matcher <span class="keyword">import</span> patch_matcher</span><br></pre></td></tr></table></figure><br>接着就可以创建插件的命令<br>nonebot本身有<code>on_command(</code>)方法,但是不方便获取参数,Moonlark使用Alconna让获取命令的参数更方便。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[command] = on_alconna(</span><br><span class="line"> Alconna(</span><br><span class="line"> <span class="string">"[command]"</span>,</span><br><span class="line"> Subcommand(<span class="string">"[subcommand]"</span>, Args[<span class="string">"[argument name]"</span>, [argument <span class="built_in">type</span>],[default value]]) </span><br><span class="line"> )</span><br><span class="line">)</span><br></pre></td></tr></table></figure><br>期中<code>[command]</code>指命令名称<br><code>[subcommand]</code>指子命令名称<br><code>[argument name]</code>指参数名称<br><code>[argument type]</code>参数类型<br><code>[default value]</code>默认值(可选)<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">lang = LangHelper() <span class="comment">#本地化</span></span><br><span class="line">patch_matcher(sudoku) <span class="comment">#启动指令配对器</span></span><br></pre></td></tr></table></figure></p><h3 id="事件处理"><a href="#事件处理" class="headerlink" title="事件处理"></a>事件处理</h3><p>Nonebot是用到了异步编程,所以很多函数都用了<code>async</code>和<code>await</code>关键字<br>我总结了一下使用规则:</p><ul><li><code>def</code>,<code>for</code>,<code>with</code>等关键字前可以使用<code>async</code>,让其异步执行;</li><li>调用使用了<code>async</code>定义的函数,需要使用<code>await</code>;</li><li>函数体中调用其他函数使用了<code>await</code>的函数(函数调用了其他异步函数),这个函数定义时要使用<code>async</code>(这个函数也一定是异步函数)</li></ul><p>主命令的事件处理<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">#记得在__init__.py加入这个</span></span><br><span class="line">require(<span class="string">"nonebot_plugin_larkutils"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#记得在__main__.py开头导入这个</span></span><br><span class="line"><span class="keyword">from</span> nonebot_plugin_larkutils <span class="keyword">import</span> get_user_id</span><br><span class="line"></span><br><span class="line"><span class="meta">@[command].assign(<span class="params"><span class="string">"$main"</span></span>)</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">def</span> <span class="title function_">_</span>(<span class="params">args : [<span class="built_in">type</span>], user_id: <span class="built_in">str</span> = get_user_id(<span class="params"></span>)</span>): <span class="comment">#参数不止一个,建议指定类型</span></span><br><span class="line">...<span class="comment">#干你想干的事情</span></span><br></pre></td></tr></table></figure></p><p>子命令就是把<code>$main</code>换成对应的子命令名称即可</p><h3 id="向用户发送消息"><a href="#向用户发送消息" class="headerlink" title="向用户发送消息"></a>向用户发送消息</h3><p>事件处理的一个重要步骤就是让机器人发送消息。</p><h4 id="Alconna发送消息"><a href="#Alconna发送消息" class="headerlink" title="Alconna发送消息"></a>Alconna发送消息</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[command].send([message])<span class="comment">#发送消息</span></span><br><span class="line">[command].finish([message])<span class="comment">#发送消息(终止事件处理)</span></span><br></pre></td></tr></table></figure><p><code>[command]</code>就是<code>on_alconna()</code>返回的<code>AlconnaMatcher()</code>对象。</p><h4 id="LangHelper发送消息"><a href="#LangHelper发送消息" class="headerlink" title="LangHelper发送消息"></a>LangHelper发送消息</h4><p>Moonlark开发工具,用于本地化。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#lang就是刚才lang=LangHelper()创建的对象</span></span><br><span class="line">lang.send(<span class="string">"key"</span>,user_id,args)</span><br><span class="line">lang.finish(<span class="string">"key"</span>,user_id,args)</span><br></pre></td></tr></table></figure><p>其中<code>key</code>是刚才本地化时添加的组件<br>访问子键时要先把父键写在前面,父键和子键用点号(<code>.</code>)连接。</p><h4 id="渲染图片模版并发送图片"><a href="#渲染图片模版并发送图片" class="headerlink" title="渲染图片模版并发送图片"></a>渲染图片模版并发送图片</h4><h5 id="导入依赖"><a href="#导入依赖" class="headerlink" title="导入依赖"></a>导入依赖</h5><p>**在<code>__init__.py</code>中<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">require(<span class="string">"nonebot_plugin_htmlrender"</span>)</span><br></pre></td></tr></table></figure></p><p><strong>在<code>__main__.py</code>中</strong><br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> nonebot_plugin_render.render <span class="keyword">import</span> render_template</span><br><span class="line"><span class="keyword">from</span> nonebot_plugin_render.cache <span class="keyword">import</span> creator</span><br></pre></td></tr></table></figure></p><h5 id="定义渲染模版函数"><a href="#定义渲染模版函数" class="headerlink" title="定义渲染模版函数"></a>定义渲染模版函数</h5><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@creator(<span class="params"><span class="string">"[command].html.jinja"</span></span>)</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">def</span> <span class="title function_">render</span>(<span class="params">content: <span class="built_in">dict</span>, user_id: <span class="built_in">str</span> = get_user_id(<span class="params"></span>)</span>):</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">await</span> render_template(<span class="string">"[command].html.jinja"</span>, <span class="string">""</span>, user_id, content, {}, <span class="literal">True</span>)</span><br></pre></td></tr></table></figure><p>使用<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="keyword">def</span> <span class="title function_">_</span>(<span class="params">user_id: <span class="built_in">str</span> = get_user_id(<span class="params"></span>)</span>):</span><br><span class="line"> ...</span><br><span class="line"> image = <span class="keyword">await</span> render([content], user_id)</span><br><span class="line"> ... </span><br></pre></td></tr></table></figure></p><p>其中<code>content</code>是记录内容的字典,要提供jinja对应的信息。</p><h5 id="发送图片"><a href="#发送图片" class="headerlink" title="发送图片"></a>发送图片</h5><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">await</span> UniMessage().image(raw=image).send(reply_to=<span class="literal">True</span>)</span><br></pre></td></tr></table></figure><p><code>reply_to</code>设置为<code>True</code>时,机器人会回复用户的消息。</p><h1 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h1><h2 id="启动Nonebot"><a href="#启动Nonebot" class="headerlink" title="启动Nonebot"></a>启动Nonebot</h2><p>在moonlark文件夹下运行命令,启动机器人</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">poetry run nb run</span><br></pre></td></tr></table></figure><h2 id="使用Matcha测试"><a href="#使用Matcha测试" class="headerlink" title="使用Matcha测试"></a>使用Matcha测试</h2><p>不推荐Napcat测试,容易被封。<br>先设置角色(角色唯一标识必须是纯数字)<br><img src="https://s1.imagehub.cc/images/2025/05/26/b321716b601f0ae56efb49be8bc42126.png" alt="image"><br>在启动Nonebot后向机器人发送消息就可以收到消息了</p>]]></content>
<summary type="html"><h1 id="往事"><a href="#往事" class="headerlink" title="往事"></a>往事</h1><p>一直<del>沉迷</del>在lingmo-webbrowser的开发中无法自拔。<br>但是,由于Qt WebEngine 一个致命的问题——如果想要支持html5视频元素,就得重新编译qt<br>这个问题很难解决<br>后来,<del>由于种种原因</d</summary>
<category term="Python" scheme="https://blog.qyadbr.top/categories/Python/"/>
<category term="机器人" scheme="https://blog.qyadbr.top/tags/%E6%9C%BA%E5%99%A8%E4%BA%BA/"/>
<category term="Nonebot2" scheme="https://blog.qyadbr.top/tags/Nonebot2/"/>
</entry>
<entry>
<title>使用Github Actions定制Github个人主页</title>
<link href="https://blog.qyadbr.top/posts/hexo14/"/>
<id>https://blog.qyadbr.top/posts/hexo14/</id>
<published>2025-04-05T15:18:47.000Z</published>
<updated>2025-05-28T13:02:17.969Z</updated>
<content type="html"><![CDATA[<h1 id="先放一张效果图"><a href="#先放一张效果图" class="headerlink" title="先放一张效果图"></a>先放一张效果图</h1><p><img src="https://cdn.jsdelivr.net/gh/admibrill/admibrill@master/metrics.svg" alt=""></p><h1 id="教程"><a href="#教程" class="headerlink" title="教程"></a>教程</h1><p>其实就是利用这个lowlighter/metrics的gh-actions来每天定时生成一张svg。<br>详细教程见<a href="https://github.com/lowlighter/metrics">lowlighter/metrics: 📊 An infographics generator with 30+ plugins and 300+ options to display stats about your GitHub account and render them as SVG, Markdown, PDF or JSON!</a></p><h1 id="metrics-yml"><a href="#metrics-yml" class="headerlink" title="metrics.yml"></a><code>metrics.yml</code></h1><p>以下就是我的同款workflow配置<br><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">Metrics</span></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line"> <span class="attr">schedule:</span> [{<span class="attr">cron:</span> <span class="string">"0 0 * * *"</span>}]</span><br><span class="line"> <span class="attr">workflow_dispatch:</span></span><br><span class="line"> <span class="attr">push:</span> {<span class="attr">branches:</span> [<span class="string">"main"</span>]}</span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line"> <span class="attr">github-metrics:</span></span><br><span class="line"> <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line"> <span class="attr">environment:</span> </span><br><span class="line"> <span class="attr">name:</span> <span class="string">production</span></span><br><span class="line"> <span class="attr">permissions:</span></span><br><span class="line"> <span class="attr">contents:</span> <span class="string">write</span></span><br><span class="line"> <span class="attr">steps:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">uses:</span> <span class="string">lowlighter/metrics@latest</span></span><br><span class="line"> <span class="attr">with:</span></span><br><span class="line"> <span class="attr">filename:</span> <span class="string">metrics.svg</span></span><br><span class="line"> <span class="attr">token:</span> <span class="string">${{</span> <span class="string">secrets.METRICS_TOKEN</span> <span class="string">}}</span></span><br><span class="line"> <span class="attr">config_timezone:</span> <span class="string">Asia/Shanghai</span></span><br><span class="line"> <span class="attr">base:</span> <span class="string">header,</span> <span class="string">activity,</span> <span class="string">community,</span> <span class="string">repositories,</span> <span class="string">metadata</span></span><br><span class="line"> </span><br><span class="line"> <span class="attr">plugin_isocalendar:</span> <span class="literal">yes</span></span><br><span class="line"> <span class="attr">plugin_isocalendar_duration:</span> <span class="string">full-year</span></span><br><span class="line"> </span><br><span class="line"> <span class="attr">plugin_lines:</span> <span class="literal">yes</span></span><br><span class="line"> <span class="attr">plugin_lines_history_limit:</span> <span class="number">1</span></span><br><span class="line"> <span class="attr">plugin_lines_sections:</span> <span class="string">base</span></span><br><span class="line"> <span class="attr">plugin_lines_delay:</span> <span class="number">30</span></span><br><span class="line"> </span><br><span class="line"> <span class="attr">plugin_languages:</span> <span class="literal">yes</span></span><br><span class="line"> <span class="attr">plugin_languages_skipped:</span> <span class="string">dotfiles</span></span><br><span class="line"> <span class="attr">plugin_languages_details:</span> <span class="string">percentage,</span> <span class="string">bytes-size</span></span><br><span class="line"> </span><br><span class="line"> <span class="attr">plugin_followup:</span> <span class="literal">yes</span></span><br><span class="line"> <span class="attr">plugin_followup_sections:</span> <span class="string">user</span></span><br><span class="line"> </span><br><span class="line"> <span class="attr">plugin_code:</span> <span class="literal">yes</span></span><br><span class="line"> <span class="attr">plugin_code_languages:</span> <span class="string">javascript,</span> <span class="string">typescript,</span> <span class="string">python,</span> <span class="string">cpp</span></span><br><span class="line"> <span class="attr">plugin_code_load:</span> <span class="number">400</span></span><br><span class="line"></span><br><span class="line"> <span class="attr">plugin_wakatime:</span> <span class="literal">yes</span></span><br><span class="line"> <span class="attr">plugin_wakatime_sections:</span> <span class="string">time,</span> <span class="string">projects,</span> <span class="string">projects-graphs,</span> <span class="string">languages,</span> <span class="string">languages-graphs,</span> <span class="string">editors,</span> <span class="string">os</span></span><br><span class="line"> <span class="attr">plugin_wakatime_token:</span> <span class="string">${{</span> <span class="string">secrets.WAKATIME_TOKEN</span> <span class="string">}}</span></span><br><span class="line"> </span><br><span class="line"> <span class="attr">plugin_rss:</span> <span class="literal">yes</span></span><br><span class="line"> <span class="attr">plugin_rss_source:</span> <span class="string">https://blog.qyadbr.top/atom.xml</span></span><br><span class="line"> <span class="attr">plugin_rss_limit:</span> <span class="number">10</span></span><br><span class="line"></span><br><span class="line"> <span class="attr">plugin_gists:</span> <span class="literal">yes</span></span><br><span class="line"></span><br><span class="line"> <span class="attr">plugin_achievements:</span> <span class="literal">yes</span></span><br><span class="line"></span><br><span class="line"> <span class="attr">plugin_activity:</span> <span class="literal">yes</span></span><br></pre></td></tr></table></figure></p>]]></content>
<summary type="html"><h1 id="先放一张效果图"><a href="#先放一张效果图" class="headerlink" title="先放一张效果图"></a>先放一张效果图</h1><p><img src="https://cdn.jsdelivr.net/gh/admibrill/admibrill@master/metrics.svg" alt=""></p>
<h1 id="教程"><a href=</summary>
<category term="Github" scheme="https://blog.qyadbr.top/categories/Github/"/>
<category term="Github-Actions" scheme="https://blog.qyadbr.top/tags/Github-Actions/"/>
</entry>
<entry>
<title>P3435 [POI 2006] OKR-Periods of Words 题解</title>
<link href="https://blog.qyadbr.top/posts/hexo13/"/>
<id>https://blog.qyadbr.top/posts/hexo13/</id>
<published>2025-03-23T12:45:44.000Z</published>
<updated>2025-05-28T13:02:21.815Z</updated>
<content type="html"><![CDATA[<h1 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h1><p>A string is a finite sequence of lower-case (non-capital) letters of the English alphabet. Particularly, it may be an empty sequence, i.e. a sequence of 0 letters. By A=BC we denotes that A is a string obtained by concatenation (joining by writing one immediately after another, i.e. without any space, etc.) of the strings B and C (in this order). A string P is a prefix of the string !, if there is a string B, that A=PB. In other words, prefixes of A are the initial fragments of A. In addition, if P!=A and P is not an empty string, we say, that P is a proper prefix of A.</p><p>A string Q is a period of Q, if Q is a proper prefix of A and A is a prefix (not necessarily a proper one) of the string QQ. For example, the strings abab and ababab are both periods of the string abababa. The maximum period of a string A is the longest of its periods or the empty string, if A doesn’t have any period. For example, the maximum period of ababab is abab. The maximum period of abc is the empty string.</p><p>Task Write a programme that:</p><p>reads from the standard input the string’s length and the string itself,calculates the sum of lengths of maximum periods of all its prefixes,writes the result to the standard output.</p><h1 id="输入格式"><a href="#输入格式" class="headerlink" title="输入格式"></a>输入格式</h1><p>In the first line of the standard input there is one integer $k$ ($1\le k\le 1\ 000\ 000$) - the length of the string. In the following line a sequence of exactly $k$ lower-case letters of the English alphabet is written - the string.</p><h1 id="输出格式"><a href="#输出格式" class="headerlink" title="输出格式"></a>输出格式</h1><p>In the first and only line of the standard output your programme should write an integer - the sum of lengths of maximum periods of all prefixes of the string given in the input.</p><h1 id="输入输出样例-1"><a href="#输入输出样例-1" class="headerlink" title="输入输出样例 #1"></a>输入输出样例 #1</h1><h2 id="输入-1"><a href="#输入-1" class="headerlink" title="输入 #1"></a>输入 #1</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">8</span><br><span class="line">babababa</span><br></pre></td></tr></table></figure><h2 id="输出-1"><a href="#输出-1" class="headerlink" title="输出 #1"></a>输出 #1</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">24</span><br></pre></td></tr></table></figure><h1 id="题意翻译"><a href="#题意翻译" class="headerlink" title="题意翻译"></a>题意翻译</h1><p>对于一个仅含小写字母的字符串 $a$,$p$ 为 $a$ 的前缀且 $p\ne a$,那么我们称 $p$ 为 $a$ 的 $proper$ 前缀。</p><p>规定字符串 Q 表示 a 的周期,当且仅当 Q 是 a 的 proper 前缀且 a 是 Q+Q 的前缀。若这样的字符串不存在,则 a 的周期为空串。</p><p>例如 <code>ab</code> 是 <code>abab</code> 的一个周期,因为 <code>ab</code> 是 <code>abab</code> 的 proper 前缀,且 <code>abab</code> 是 <code>ab</code>+<code>ab</code> 的前缀。</p><p>求给定字符串所有前缀的最大周期长度之和。</p><h1 id="解析"><a href="#解析" class="headerlink" title="解析"></a>解析</h1><p>首先介绍一个叫$next$数组的东西<br>因为当匹配失败时,就会利用$next$数组往前跳,这样就能节省匹配次数<br>$next$简称$ne$.<br>对于一个字符串$s$ ,对应的 $ne_i$ 定义为 $s$ 长度为 $i$ 的前缀的最长公共前后缀的长度。<br>例如,给定一个 $s =$ <code>abacabad</code>.</p><div class="table-container"><table><thead><tr><th style="text-align:center">$i$</th><th style="text-align:center">1</th><th style="text-align:center">2</th><th style="text-align:center">3</th><th style="text-align:center">4</th><th style="text-align:center">5</th><th style="text-align:center">6</th><th style="text-align:center">7</th><th style="text-align:center">8</th></tr></thead><tbody><tr><td style="text-align:center">$s_i$</td><td style="text-align:center"><code>a</code></td><td style="text-align:center"><code>b</code></td><td style="text-align:center"><code>a</code></td><td style="text-align:center"><code>c</code></td><td style="text-align:center"><code>a</code></td><td style="text-align:center"><code>b</code></td><td style="text-align:center"><code>a</code></td><td style="text-align:center"><code>d</code></td></tr><tr><td style="text-align:center">$ne_i$</td><td style="text-align:center">0</td><td style="text-align:center">0</td><td style="text-align:center">1</td><td style="text-align:center">0</td><td style="text-align:center">1</td><td style="text-align:center">2</td><td style="text-align:center">3</td><td style="text-align:center">0</td></tr></tbody></table></div><p>这段代码可以求出$ne$数组:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">ne[<span class="number">1</span>]=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">2</span>,j=<span class="number">0</span>;i<=n;i++){</span><br><span class="line"><span class="keyword">while</span>(j&&s[i]!=s[j<span class="number">+1</span>])j=ne[j];</span><br><span class="line"><span class="keyword">if</span>(s[i]==s[j<span class="number">+1</span>])j++;</span><br><span class="line">ne[i]=j;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>整个过程就是,如果能匹配,就一直往前进(<code>j++</code>);否则,不断地利用之前的信息往回跳(<code>j=ne[j]</code>),直到可以匹配为止。</p><p>设 $Q_{max}$ 为字符串的最大周期。那么:</p><div class="table-container"><table><thead><tr><th>$i$</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr></thead><tbody><tr><td>$Q_{max}$</td><td><code>a</code></td><td><code>b</code></td><td><code>a</code></td><td><code>b</code></td><td></td><td></td><td></td><td></td></tr><tr><td>$s$</td><td><code>a</code></td><td><code>b</code></td><td><code>a</code></td><td><code>b</code></td><td><code>a</code></td><td><code>b</code></td><td></td><td></td></tr><tr><td>$Q<em>{max}Q</em>{max}$</td><td><code>a</code></td><td><code>b</code></td><td><code>a</code></td><td><code>b</code></td><td><code>a</code></td><td><code>b</code></td><td><code>a</code></td><td><code>b</code></td></tr></tbody></table></div><p>所以,对于一个字符串 $s$ , 它的 $|Q_{max}|$ 就是$|s|-$它最短公共前后缀的长度。<br>最短公共前后缀的长度不好求,但是我们发现可以通过不断<code>j=ne[j]</code>求得。</p><p>于是就有了这样一段代码,一趟循环求得本题答案:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line">now=i;</span><br><span class="line"><span class="keyword">while</span>(ne[now])now=ne[now];</span><br><span class="line"><span class="keyword">if</span>(ne[i]!=<span class="number">0</span>)ne[i]=now;</span><br><span class="line">ans+=i-now;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h1 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</h1><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> N=<span class="number">1000086</span>;</span><br><span class="line"><span class="type">int</span> n,ne[N],now;</span><br><span class="line"><span class="type">char</span> s[N];</span><br><span class="line"><span class="type">long</span> <span class="type">long</span> ans;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"> cin>>n>>s<span class="number">+1</span>;</span><br><span class="line"> ne[<span class="number">1</span>]=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">2</span>,j=<span class="number">0</span>;i<=n;i++){</span><br><span class="line"> <span class="keyword">while</span>(j&&s[i]!=s[j<span class="number">+1</span>])j=ne[j];</span><br><span class="line"> <span class="keyword">if</span>(s[i]==s[j<span class="number">+1</span>])j++;</span><br><span class="line"> ne[i]=j;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> now=i;</span><br><span class="line"> <span class="keyword">while</span>(ne[now])now=ne[now];</span><br><span class="line"> <span class="keyword">if</span>(ne[i]!=<span class="number">0</span>)ne[i]=now;</span><br><span class="line"> ans+=i-now;</span><br><span class="line"> }</span><br><span class="line"> cout<<ans;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h1><p>A string is a finite sequence of lower-case (non-capital) letters of the English alphabet. Particularly, it may be an empt</summary>
<category term="题解" scheme="https://blog.qyadbr.top/categories/%E9%A2%98%E8%A7%A3/"/>
<category term="题解" scheme="https://blog.qyadbr.top/tags/%E9%A2%98%E8%A7%A3/"/>
</entry>
<entry>
<title>Qt Troubleshoot(三)</title>
<link href="https://blog.qyadbr.top/posts/hexo12/"/>
<id>https://blog.qyadbr.top/posts/hexo12/</id>
<published>2025-01-20T02:21:09.000Z</published>
<updated>2025-05-28T13:02:28.252Z</updated>
<content type="html"><![CDATA[<h1 id="1-setWindowFlags-Qt-WindowType-WindowStayOnTopHint-窗口隐藏"><a href="#1-setWindowFlags-Qt-WindowType-WindowStayOnTopHint-窗口隐藏" class="headerlink" title="1.setWindowFlags(Qt.WindowType.WindowStayOnTopHint)窗口隐藏"></a>1.<code>setWindowFlags(Qt.WindowType.WindowStayOnTopHint)</code>窗口隐藏</h1><p>制作了一个可以自动显示的窗口类,实例化后自动显示,无需<code>window.show()</code>。但是,在<code>show()</code>之后又通过<code>setWindowFlags()</code>方法设置窗口置顶时:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PySide6.QtWidgets <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> PySide6.QtCore <span class="keyword">import</span> *</span><br><span class="line">app=QApplication()</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyWindow</span>(<span class="title class_ inherited__">QWidget</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__()</span><br><span class="line"> <span class="variable language_">self</span>.show()</span><br><span class="line"> <span class="variable language_">self</span>.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)</span><br><span class="line">window=MyWindow()</span><br><span class="line">app.<span class="built_in">exec</span>()</span><br></pre></td></tr></table></figure><p>这个窗口刚显示出来就隐藏了。<br>我想这也是为什么<code>Qt</code>的窗口不会自动显示的原因之一。但是如果一定要在构造函数里面自动显示,而且<code>setWindowFlags()</code>必须放在<code>show()</code>的后面的时候,就会出现这个问题。</p><p>当然,可以在设置完之后再显示一次。但是,这样窗口还是会隐藏,在用户看来就是窗口闪了一下。</p><h2 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h2><p>所以,以后在调用了<code>show()</code>之后就不要用<code>setWindowFlags()</code>来设置窗口置顶了。(经过测试,设置其他的还行,比如说设置无边框就没有这种问题)<br>改成用<code>window.windowHandle().setFlags()</code>,作用是相同的,但是窗口不会隐藏。</p><h1 id="2-window-hasFocus-不能正确判断窗口焦点"><a href="#2-window-hasFocus-不能正确判断窗口焦点" class="headerlink" title="2.window.hasFocus()不能正确判断窗口焦点"></a>2.<code>window.hasFocus()</code>不能正确判断窗口焦点</h1><p>其实,<code>window.hasFocus()</code>并不是不能正确判断窗口焦点,它只判断这个窗口内的这个元件是否有焦点。焦点也不是自动变化的,而是要通过<code>setFocus()</code>来转移焦点到当前原件上。当窗口有焦点(窗口被点击,被系统置于所有其他窗口的上方)时,并不会自动调用<code>setFocus()</code>。</p><p>在窗口的<code>mousePressEvent()</code>中调用<code>setFocus</code>不是一种正确的做法。因为这样确实让<code>hasFocus()</code>返回的值变为<code>True</code>了,但是这将影响到里面元件的焦点。窗口和里面的所有元件中只能有一个有焦点,与窗口与其他窗口的只有一个的焦点不是同一个。</p><p>所以,<code>QWidget</code>专门提供了一个函数来判断当前窗口和其他窗口中,只有一个窗口有的那个焦点,在不在窗口上。这个函数就是:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">window.isActiveWindow()</span><br></pre></td></tr></table></figure></p><p>当然,对应地,<code>setFocus()</code>函数也是只对当前元件所在窗口内的,如果需要设置窗口的全局焦点,那么方法名字应改为:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">window.activateWindow()</span><br></pre></td></tr></table></figure></p><h1 id="3-setWindowIcon-不改变任务栏图标"><a href="#3-setWindowIcon-不改变任务栏图标" class="headerlink" title="3.setWindowIcon()不改变任务栏图标"></a>3.<code>setWindowIcon()</code>不改变任务栏图标</h1><p>开发应用程序时,常常需要把窗口的图标改成自己的图标。设置的方法很简单,就是<code>window.setWindowIcon()</code>。<br>所以写了一个设置图标的测试程序:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PySide6.QtWidgets <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> PySide6.QtCore <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> PySide6.QtGui <span class="keyword">import</span> *</span><br><span class="line">app=QApplication()</span><br><span class="line">window=QWidget()</span><br><span class="line">window.setWindowIcon(QPixmap(<span class="string">'../icon.png'</span>))</span><br><span class="line">window.show()</span><br><span class="line">app.<span class="built_in">exec</span>()</span><br></pre></td></tr></table></figure><br>运行效果如图:<br><img src="https://s1.imagehub.cc/images/2025/01/20/3a7403e181cf89c2e0a2040a591cf698.png" alt="image"><br>可以看到,窗口左上角图标和任务栏图标悬停后显示的缩略图的左上角图标都被设置了。但是任务栏上的那个图标没有被设置。<br>这个是Windows系统的一个问题,Windows认为所有的Python程序都是同一个appid,所以所有打开的窗口都显示同意个图标,Python的图标。为了修改appid,我们只能利用<code>ctypes</code>库访问系统dll。<br>为了防止程序在其他操作系统报错无法执行,这段代码外面要加上一层<code>try...except</code>语句。<br>在导入库之后紧接着加入这段代码:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span>:</span><br><span class="line"> <span class="keyword">from</span> ctypes <span class="keyword">import</span> windll</span><br><span class="line"> windll.shell32.SetCurrentProcessExplicitAppUserModelID(<span class="string">'<your appid>'</span>)</span><br><span class="line"><span class="keyword">except</span> ImportError:</span><br><span class="line"> <span class="keyword">pass</span></span><br></pre></td></tr></table></figure><br>把<code><your appid></code>替换为一个字符串,建议包含一些有关应用程序的信息,每条信息用<code>.</code>隔开。<br>最终效果:<br><img src="https://s1.imagehub.cc/images/2025/01/20/7a13b0e65efa7bd8b5936b830996df3f.png" alt="image"></p>]]></content>
<summary type="html"><h1 id="1-setWindowFlags-Qt-WindowType-WindowStayOnTopHint-窗口隐藏"><a href="#1-setWindowFlags-Qt-WindowType-WindowStayOnTopHint-窗口隐藏" class="headerlink" title="1.setWindowFlags(Qt.WindowType.WindowStayO</summary>
<category term="Qt Troubleshoot" scheme="https://blog.qyadbr.top/categories/Qt-Troubleshoot/"/>
<category term="Qt" scheme="https://blog.qyadbr.top/tags/Qt/"/>
</entry>
<entry>
<title>Qt Troubleshoot(二)</title>
<link href="https://blog.qyadbr.top/posts/hexo11/"/>
<id>https://blog.qyadbr.top/posts/hexo11/</id>
<published>2025-01-18T02:47:34.000Z</published>
<updated>2025-05-28T13:02:34.795Z</updated>
<content type="html"><![CDATA[<p>最近在研究Qt的过程中,又积攒了一些问题,下面是解决方案。</p><h1 id="1-QColor-lighter-与QColor-darker"><a href="#1-QColor-lighter-与QColor-darker" class="headerlink" title="1.QColor.lighter()与QColor.darker()"></a>1.<code>QColor.lighter()</code>与<code>QColor.darker()</code></h1><p>在Qml中,使用<code>Qt.lighter()</code>和<code>Qt.darker()</code>来让颜色变得更亮或更暗。括号里填的是相比原来颜色亮了或暗了多少倍,值在1左右。<br>但是,如果这样使用到<code>QtWidgets</code>中,<code>lighter</code>的效果会很暗,<code>darker</code>的效果会很亮,反而达到了相反的效果。</p><p>这是因为,在Python程序文件中,括号内的值要乘以100,QColor是按原来的百分之多少来把颜色变亮或变暗的。</p><h1 id="2-Qt同时继承两个类,窗口闪退"><a href="#2-Qt同时继承两个类,窗口闪退" class="headerlink" title="2.Qt同时继承两个类,窗口闪退"></a>2.Qt同时继承两个类,窗口闪退</h1><p>有一次,我继承<code>QFrame</code>自己定义了一个<code>Frame</code>类,这个类带有自动显示、鼠标事件检测等功能。<br>但是,<code>QFrame</code>是没有显示文字的功能的,所以我就尝试,制作一个<code>Label</code>类,同时继承(即载括号里写两个父类)可不可以呢?</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Label</span>(Frame,QLabel):</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,parent=<span class="literal">None</span>,show=<span class="literal">True</span>,autoAdjust=<span class="literal">True</span></span>):</span><br><span class="line"><span class="keyword">global</span> widgetCount</span><br><span class="line"><span class="built_in">super</span>().__init__(parent)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>当然,窗口刚显示就直接消失了,这个可能就是Qt的一个问题,所以建议以后不要同时继承两个Qt类(Frame是继承QFrame的,所以也算)。</p><h1 id="3-QWidget-mouseMoveEvent-点击鼠标再移动才触发事件"><a href="#3-QWidget-mouseMoveEvent-点击鼠标再移动才触发事件" class="headerlink" title="3.QWidget.mouseMoveEvent()点击鼠标再移动才触发事件"></a>3.<code>QWidget.mouseMoveEvent()</code>点击鼠标再移动才触发事件</h1><p>这也是Qt的一个bug。<br>解决这个问题的方法很简单,在自己定义的类的构造函数(<code>__init__()</code>)中加入这么一行:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class YourWidget(QWidget):</span></span><br><span class="line"><span class="comment"># def __init__(self):</span></span><br><span class="line"><span class="comment"># 其他内容</span></span><br><span class="line"><span class="variable language_">self</span>.setMouseTracking(<span class="literal">True</span>)</span><br></pre></td></tr></table></figure></p><p>这样,鼠标直接在窗口中移动,<code>mouseMoveEvent()</code>也能触发了。</p><h1 id="4-如何设置窗口即无边框又圆角"><a href="#4-如何设置窗口即无边框又圆角" class="headerlink" title="4.如何设置窗口即无边框又圆角"></a>4.如何设置窗口即无边框又圆角</h1><p>制作组件的时候,常常需要自定义一些样式。比如我需要无边框圆角窗口。<br>于是就有了这样的代码:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PySide6.QtWidgets <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> PySide6.QtCore <span class="keyword">import</span> *</span><br><span class="line">app=QApplication()</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyWindow</span>(<span class="title class_ inherited__">QWidget</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__()</span><br><span class="line"> <span class="variable language_">self</span>.setWindowFlags(Qt.WindowType.FramelessWindowHint)</span><br><span class="line"> <span class="variable language_">self</span>.setStyleSheet(<span class="string">'border-radius: 4'</span>)</span><br><span class="line">window=MyWindow()</span><br><span class="line">window.show()</span><br><span class="line">app.<span class="built_in">exec</span>()</span><br></pre></td></tr></table></figure></p><p>但是,效果并不好,没有圆角:</p><p><img src="https://s1.imagehub.cc/images/2025/01/18/0a44771ae8c21cc9aebca90f95f14e48.png" alt="image"></p><p>这是因为Windows窗口不能设置圆角。但是可以把窗口透明,然后自己做一个背景控件再设置背景控件的圆角。因为背景是控件,所以是可以设置圆角样式的。</p><p>最终代码:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PySide6.QtWidgets <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> PySide6.QtCore <span class="keyword">import</span> *</span><br><span class="line">app=QApplication()</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyWindow</span>(<span class="title class_ inherited__">QWidget</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__()</span><br><span class="line"> <span class="variable language_">self</span>.setWindowFlags(Qt.WindowType.FramelessWindowHint)</span><br><span class="line"> <span class="variable language_">self</span>.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)</span><br><span class="line"> <span class="variable language_">self</span>.setStyleSheet(<span class="string">'background-color:transparent'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.background1=QWidget(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.background1.resize(<span class="variable language_">self</span>.size())</span><br><span class="line"> <span class="variable language_">self</span>.background1.setStyleSheet(<span class="string">'background-color:#FFFFFF;border-radius: 10'</span>)</span><br><span class="line">window=MyWindow()</span><br><span class="line">window.show()</span><br><span class="line">app.<span class="built_in">exec</span>()</span><br></pre></td></tr></table></figure></p><p>效果:<br><img src="https://s1.imagehub.cc/images/2025/01/18/0a74223a771be8410bcf10f1e1d7b898.png" alt="image"></p>]]></content>
<summary type="html"><p>最近在研究Qt的过程中,又积攒了一些问题,下面是解决方案。</p>
<h1 id="1-QColor-lighter-与QColor-darker"><a href="#1-QColor-lighter-与QColor-darker" class="headerlink" title="1.QColor.lighter()与QColor.darker()"></a>1.<code>QColo</summary>
<category term="Qt Troubleshoot" scheme="https://blog.qyadbr.top/categories/Qt-Troubleshoot/"/>
<category term="Qt" scheme="https://blog.qyadbr.top/tags/Qt/"/>
</entry>
<entry>
<title>Qt Troubleshoot (一)</title>
<link href="https://blog.qyadbr.top/posts/hexo10/"/>
<id>https://blog.qyadbr.top/posts/hexo10/</id>
<published>2024-12-30T12:38:31.000Z</published>
<updated>2025-05-28T13:02:40.775Z</updated>
<content type="html"><![CDATA[<h1 id="建立这个分类的目的"><a href="#建立这个分类的目的" class="headerlink" title="建立这个分类的目的"></a>建立这个分类的目的</h1><p>自从开始用Qt来编写应用程序之后,我发现应用的开发变得方便了许多。当然,图中难免遇到问题。我会在这个分类不断记录我遇到的问题以及我的解决过程。</p><h1 id="1-QLabel自动换行"><a href="#1-QLabel自动换行" class="headerlink" title="1.QLabel自动换行"></a>1.<code>QLabel</code>自动换行</h1><h2 id="描述"><a href="#描述" class="headerlink" title="描述"></a>描述</h2><p>我在使用<code>QtWidgets.QLabel</code>时,常常需要一个自动换行功能。查阅Qt官网,发现<code>QLabel</code>有个<code>setWordWrap()</code>方法。但是,有时即使设置了为<code>True</code>,它任然没有换行。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PySide6.QtWidgets <span class="keyword">import</span> *</span><br><span class="line">app=QApplication([])</span><br><span class="line">window=QWidget()</span><br><span class="line">label=QLabel(<span class="string">'LongWordTestLongWordTestLongWordTestLongWordTestLongWordTest'</span>,window)</span><br><span class="line">label.setWordWrap(<span class="literal">True</span>)</span><br><span class="line">window.resize(<span class="number">500</span>,<span class="number">500</span>)</span><br><span class="line">window.show()</span><br><span class="line">app.<span class="built_in">exec</span>()</span><br></pre></td></tr></table></figure><h2 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h2><p>这是因为<code>QLabel</code>只会在有空格的地方换行。所以,纯数字和纯字母都会认为是只有一个单词,所以就不会换行了。<br>当然,纯汉字也是会正常换行的。</p><h1 id="2-自定义类继承QWidget不能设置样式"><a href="#2-自定义类继承QWidget不能设置样式" class="headerlink" title="2.自定义类继承QWidget不能设置样式"></a>2.自定义类继承<code>QWidget</code>不能设置样式</h1><h2 id="描述-1"><a href="#描述-1" class="headerlink" title="描述"></a>描述</h2><p>一次,我利用<code>QWidget</code>来制作一个自己的窗口类,让它的对象实例化后自动显示。这个实现也很简单,这是一个简化的例子:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PySide6.QtWidgets <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CustomWindow</span>(<span class="title class_ inherited__">QWidget</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__()</span><br><span class="line"> <span class="variable language_">self</span>.show()</span><br><span class="line">app=QApplication([])</span><br><span class="line">window=CustomWindow()</span><br><span class="line">window.resize(<span class="number">500</span>,<span class="number">500</span>)</span><br><span class="line">app.<span class="built_in">exec</span>()</span><br></pre></td></tr></table></figure></p><p>后来,我有想设置一个初始的样式,把它的背景色设成绿色,在<code>__init__(self)</code>里面加了一行:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">self</span>.setStyleSheet(<span class="string">'background-color: green;'</span>)</span><br></pre></td></tr></table></figure></p><p>结果竟然是,<code>QWidget</code>还是那个<code>QWidget</code>,背景还是那个初始颜色,根本不是绿色</p><h2 id="解决-1"><a href="#解决-1" class="headerlink" title="解决"></a>解决</h2><p>经过了研究,我发现可能是有时<code>QWidget</code>的子类是不会自动设样式表的(在一个复杂的项目中我遇到了此问题,当我尝试简化时,这个问题消失了,但是这个问题一定存在)。<br>有两种解决方法。</p><h3 id="第一种:改变父类"><a href="#第一种:改变父类" class="headerlink" title="第一种:改变父类"></a>第一种:改变父类</h3><p><code>QWidget</code>可能有问题,但是<code>QFrame</code>不会有问题。改成继承<code>QFrame</code>就可以了。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CustomWindow</span>(<span class="title class_ inherited__">QFrame</span>):</span><br></pre></td></tr></table></figure></p><h3 id="第二种:设置控件属性"><a href="#第二种:设置控件属性" class="headerlink" title="第二种:设置控件属性"></a>第二种:设置控件属性</h3><p>这个问题的根本就是<code>QWidget</code>的背景样式没有启用哦。可以设置控件样式(<code>QWidget.setAttribute()</code>)来启用。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">window.setAttribute(Qt.WidgetAttribute.WA_StyledBackground,<span class="literal">True</span>)</span><br></pre></td></tr></table></figure></p><h1 id="3-QWidget-setStyleSheet-覆盖之前的样式表"><a href="#3-QWidget-setStyleSheet-覆盖之前的样式表" class="headerlink" title="3.QWidget.setStyleSheet()覆盖之前的样式表"></a>3.<code>QWidget.setStyleSheet()</code>覆盖之前的样式表</h1><h2 id="描述-2"><a href="#描述-2" class="headerlink" title="描述"></a>描述</h2><p>刚才说了,<code>setStyleSheet()</code>方法可以设设置<code>QWidget</code>的样式表。然而,每次设置之后都会覆盖原有的。</p><h2 id="解决-2"><a href="#解决-2" class="headerlink" title="解决"></a>解决</h2><p>解决的方法不是很复杂,可以自己定义一个类,设置一个<code>styleSheets</code>属性(和<code>QWidget</code>原有的<code>styleSheet()</code>方法区分开)<br>在自己写一个<code>addStyleSheet()</code>方法来维护它。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">LingmoFrame</span>(<span class="title class_ inherited__">QFrame</span>):</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,parent=<span class="literal">None</span>,show=<span class="literal">True</span></span>):</span><br><span class="line"><span class="built_in">super</span>().__init__(parent)</span><br><span class="line"><span class="variable language_">self</span>.timer=QTimer()</span><br><span class="line"><span class="variable language_">self</span>.timer.timeout.connect(<span class="variable language_">self</span>.updateEvent)</span><br><span class="line"><span class="variable language_">self</span>.timer.timeout.connect(<span class="variable language_">self</span>.__update__)</span><br><span class="line"><span class="variable language_">self</span>.timer.start(timerDelay)</span><br><span class="line"><span class="keyword">if</span> show:</span><br><span class="line"><span class="variable language_">self</span>.show()</span><br><span class="line"><span class="variable language_">self</span>.styleSheets={}</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">__update__</span>(<span class="params">self</span>):</span><br><span class="line"><span class="variable language_">self</span>.update()</span><br><span class="line">styleSheetString=<span class="string">''</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="variable language_">self</span>.styleSheets:</span><br><span class="line">styleSheetString+=i+<span class="string">': '</span>+<span class="variable language_">self</span>.styleSheets[i]+<span class="string">';'</span></span><br><span class="line"><span class="variable language_">self</span>.setStyleSheet(styleSheetString)</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">updateEvent</span>(<span class="params">self</span>):</span><br><span class="line"><span class="keyword">pass</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">addStyleSheet</span>(<span class="params">self,name,style</span>):</span><br><span class="line"><span class="variable language_">self</span>.styleSheets[name]=<span class="built_in">str</span>(style)</span><br></pre></td></tr></table></figure></p><p>这个方法还贴心地将<code>style</code>转换成字符串类型,这样每次数值就不需要强转了。</p><h1 id="结束"><a href="#结束" class="headerlink" title="结束"></a>结束</h1><p>篇幅有限,最近的问题也没收集多少,所以这篇文章到这里就结束了。<br>2024年还有两天(算今天)就要过去,2025年就要来了。祝大家元旦快乐!Bye!</p>]]></content>
<summary type="html"><h1 id="建立这个分类的目的"><a href="#建立这个分类的目的" class="headerlink" title="建立这个分类的目的"></a>建立这个分类的目的</h1><p>自从开始用Qt来编写应用程序之后,我发现应用的开发变得方便了许多。当然,图中难免遇到问题。我会在这个分类不断记录我遇到的问题以及我的解决过程。</p>
<h1 id="1-QLabel自动换行"><a h</summary>
<category term="Qt Troubleshoot" scheme="https://blog.qyadbr.top/categories/Qt-Troubleshoot/"/>
<category term="Qt" scheme="https://blog.qyadbr.top/tags/Qt/"/>
</entry>
<entry>
<title>使用Qt实现一个简易时钟应用</title>
<link href="https://blog.qyadbr.top/posts/hexo9/"/>
<id>https://blog.qyadbr.top/posts/hexo9/</id>
<published>2024-12-08T01:39:37.000Z</published>
<updated>2025-05-28T13:02:44.483Z</updated>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>我使用Qt制作了一个时钟应用,现在来分享一下实现的过程。</p><p>这个小项目包括了四个部分:</p><ul><li>时钟(显示当前时间)</li><li>秒表(正向计时器,支持记录时间)</li><li>倒计时</li><li>闹钟</li></ul><h1 id="各种准备工作"><a href="#各种准备工作" class="headerlink" title="各种准备工作"></a>各种准备工作</h1><h2 id="导入"><a href="#导入" class="headerlink" title="导入"></a>导入</h2><p>制作这个应用,我使用了一大堆<code>QtWidgets</code>组件。同时,还有至关重要的<code>time</code>模块。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PySide6.QtWidgets <span class="keyword">import</span> (QApplication,QWidget,QPushButton,QGroupBox,QLabel,</span><br><span class="line"> QTableWidget,QTableWidgetItem,QProgressBar,QScrollArea,</span><br><span class="line"> QDialog,QGridLayout,QVBoxLayout,QHBoxLayout,QSpinBox,QLineEdit,QComboBox,QSystemTrayIcon,QCheckBox)</span><br><span class="line"><span class="keyword">from</span> PySide6.QtGui <span class="keyword">import</span> QIcon,QFont</span><br><span class="line"><span class="keyword">from</span> PySide6.QtCore <span class="keyword">import</span> QObject,QTimer,Qt,QSize</span><br><span class="line"><span class="keyword">import</span> time</span><br></pre></td></tr></table></figure><p>然后,建立一个<code>QApplication</code>,定义一些常量。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">qapp=QApplication([])</span><br><span class="line">icon=QIcon(<span class="string">'../media/images/1.png'</span>) <span class="comment">#窗口图标</span></span><br><span class="line">widgetslist=[] <span class="comment">#每个模式对应一个窗格</span></span><br><span class="line">musicUrlList=[<span class="string">'../media/audio/1.wav'</span>] <span class="comment">#闹铃音乐</span></span><br><span class="line">musicNameList=[<span class="string">'音乐1'</span>] <span class="comment">#音乐名称</span></span><br><span class="line"></span><br><span class="line">menubuttonnamelist=[<span class="string">'时钟'</span>,<span class="string">'秒表'</span>,<span class="string">'倒计时'</span>,<span class="string">'闹钟'</span>]</span><br><span class="line">menubuttonlist=[]</span><br><span class="line">mode=<span class="number">0</span> <span class="comment">#当前的模式</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#下面这段永远放在最后</span></span><br><span class="line">qapp.<span class="built_in">exec</span>()</span><br></pre></td></tr></table></figure><h2 id="建立窗口"><a href="#建立窗口" class="headerlink" title="建立窗口"></a>建立窗口</h2><p>建立一个类,继承<code>QtWidgets.QWidget</code>。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Window</span>(<span class="title class_ inherited__">QWidget</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,width,height,title,icon</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__()</span><br><span class="line"> <span class="variable language_">self</span>.setWindowTitle(QObject.tr(title))</span><br><span class="line"> <span class="variable language_">self</span>.resize(width,height)</span><br><span class="line"> <span class="variable language_">self</span>.setWindowIcon(icon)</span><br></pre></td></tr></table></figure><p>实例化窗口对象。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mainWindow=Window(<span class="number">1000</span>,<span class="number">600</span>,<span class="string">'时钟'</span>,icon)</span><br><span class="line">mainWindow.show()</span><br></pre></td></tr></table></figure><h2 id="功能窗格与切换按钮"><a href="#功能窗格与切换按钮" class="headerlink" title="功能窗格与切换按钮"></a>功能窗格与切换按钮</h2><p>我在窗口左侧做了四个按钮,分别对应四种功能。点击按钮就可以切换窗格的显示状态。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#定义按钮类</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MenuButton</span>(<span class="title class_ inherited__">QPushButton</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,parent,num</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__(parent)</span><br><span class="line"> <span class="variable language_">self</span>.num=num</span><br><span class="line"> <span class="variable language_">self</span>.clicked.connect(<span class="variable language_">self</span>.toggleMode)</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">toggleMode</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">global</span> mode</span><br><span class="line"> widgetslist[mode].hide()</span><br><span class="line"> widgetslist[<span class="variable language_">self</span>.num].show()</span><br><span class="line"> mode=<span class="variable language_">self</span>.num</span><br><span class="line"><span class="comment">#显示</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(menubuttonnamelist)):</span><br><span class="line"> button=MenuButton(mainWindow,i)</span><br><span class="line"> button.setText(menubuttonnamelist[i])</span><br><span class="line"> button.move(<span class="number">10</span>,<span class="number">10</span>+i*<span class="number">30</span>)</span><br><span class="line"> button.show()</span><br><span class="line"> menubuttonlist.append(button)</span><br><span class="line"> group=QGroupBox(parent=mainWindow,title=menubuttonnamelist[i])</span><br><span class="line"> group.resize(<span class="number">890</span>,<span class="number">580</span>)</span><br><span class="line"> group.move(<span class="number">100</span>,<span class="number">10</span>)</span><br><span class="line"> widgetslist.append(group)</span><br></pre></td></tr></table></figure><h2 id="窗格尺寸自适应"><a href="#窗格尺寸自适应" class="headerlink" title="窗格尺寸自适应"></a>窗格尺寸自适应</h2><p>当缩放窗口时,窗格的大小不会改变,因此我们要自动设置窗格的尺寸。</p><p>在<code>Qt</code>中,<code>QWidget</code>被缩放大小就会自动执行<code>resizeEvent</code>函数,重写其内容即可。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Window(QWidget):</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">resizeEvent</span>(<span class="params">self,event</span>):</span><br><span class="line"> size=<span class="variable language_">self</span>.size()</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> widgetslist:</span><br><span class="line"> i.resize(size.width()-<span class="number">110</span>,size.height()-<span class="number">20</span>)</span><br></pre></td></tr></table></figure><h1 id="时间显示"><a href="#时间显示" class="headerlink" title="时间显示"></a>时间显示</h1><p>这是整个项目最最简单的一部分。</p><h2 id="组件"><a href="#组件" class="headerlink" title="组件"></a>组件</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">nowtime=time.strftime(<span class="string">'%H:%M:%S'</span>)</span><br><span class="line">labelTime=QLabel(widgetslist[<span class="number">0</span>])</span><br><span class="line">font=QFont(<span class="string">'Arian'</span>,<span class="number">100</span>,<span class="number">10</span>)</span><br><span class="line">labelTime.setFont(font)</span><br><span class="line">labelTime.setText(nowtime)</span><br></pre></td></tr></table></figure><h2 id="更新显示"><a href="#更新显示" class="headerlink" title="更新显示"></a>更新显示</h2><p>除了刷新时间,还设置了窗口自适应</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">update</span>():</span><br><span class="line"> size1_1=widgetslist[<span class="number">0</span>].size()</span><br><span class="line"> nowtime=time.strftime(<span class="string">'%H:%M:%S'</span>)</span><br><span class="line"> labelTime.setText(nowtime)</span><br><span class="line"> labelTime.move(size1_1.width()/<span class="number">2</span>-size2.width()/<span class="number">2</span>,size1_1.height()/<span class="number">2</span>-size2.height()/<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">timer=QTimer()</span><br><span class="line">timer.start(<span class="number">0.05</span>)</span><br><span class="line">timer.timeout.connect(update)</span><br></pre></td></tr></table></figure><h2 id="效果"><a href="#效果" class="headerlink" title="效果"></a>效果</h2><p><img src="https://s1.imagehub.cc/images/2024/12/03/5eb951eea3aace8e6aee72c6a5ba299b.png" alt="image"></p><h1 id="正向计时器"><a href="#正向计时器" class="headerlink" title="正向计时器"></a>正向计时器</h1><p>这是第二个功能,需要实现一个可以开始、暂停的计时器,计时状态下可以记录,非计时状态下可以清零。</p><h2 id="创建组件"><a href="#创建组件" class="headerlink" title="创建组件"></a>创建组件</h2><p>实现它,需要一个文本显示,三个按钮,以及一个表格。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">recorder=QLabel(widgetslist[<span class="number">1</span>])</span><br><span class="line">recorder.setText(<span class="string">'00:00:00.000'</span>)</span><br><span class="line">recorder.setFont(font)</span><br><span class="line">startStopButton=QPushButton(<span class="string">'开始'</span>,widgetslist[<span class="number">1</span>])</span><br><span class="line">recordButton=QPushButton(<span class="string">'记录'</span>,widgetslist[<span class="number">1</span>])</span><br><span class="line">recordButton.setDisabled(<span class="literal">True</span>)</span><br><span class="line">clearButton=QPushButton(<span class="string">'清零'</span>,widgetslist[<span class="number">1</span>])</span><br><span class="line">clearButton.setDisabled(<span class="literal">True</span>)</span><br><span class="line">recordTable=QTableWidget(<span class="number">0</span>,<span class="number">3</span>,widgetslist[<span class="number">1</span>])</span><br><span class="line">recordTable.setHorizontalHeaderLabels([<span class="string">'序次'</span>,<span class="string">'间隔'</span>,<span class="string">'总计'</span>])</span><br><span class="line">recordTable.verticalHeader().setVisible(<span class="literal">False</span>)</span><br><span class="line">recordTable.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)</span><br><span class="line">recordTable.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)</span><br></pre></td></tr></table></figure><h2 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">startTimeStamp=<span class="number">0</span></span><br><span class="line">lastEndStamp=<span class="number">0</span></span><br><span class="line">lastRecordStamp=<span class="number">0</span></span><br><span class="line">running=<span class="literal">False</span></span><br><span class="line">timeDelta=<span class="number">0</span></span><br></pre></td></tr></table></figure><ul><li><code>startTimeStamp</code>:计时开始的时间戳</li><li><code>lastEndStamp</code>:上次暂停时的时间戳</li><li><code>lastRecordStamp</code>:上次记录时的时间戳,用于计算记录间隔</li><li><code>running</code>:是否正在计时</li><li><code>timeDelta</code>:暂停后,将产生时间差,在计算当前时间是要减去这个时间差<h2 id="获取与格式化时间戳"><a href="#获取与格式化时间戳" class="headerlink" title="获取与格式化时间戳"></a>获取与格式化时间戳</h2></li></ul><p>变量已经齐全,下一步就是获取当前的时间。获取时间可以使用下面简单的公式:</p><script type="math/tex; mode=display">res=now-startTimeStamp-timeDelta</script><p>这个公式要使用多次,所以封装成函数:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">getTime</span>():</span><br><span class="line"> <span class="keyword">global</span> startTimeStamp,timeDelta</span><br><span class="line"> <span class="keyword">return</span> time.time()-startTimeStamp-timeDelta </span><br></pre></td></tr></table></figure><p>获取到时间之后,将时间戳直接展示给用户肯定不现实,因此将其转换成时间字符串。同时,要传入一个参数,表示取整还是精确到小数点后三位。(后续倒计时和闹钟都不取后三位。)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">formatTime</span>(<span class="params">data,<span class="built_in">round</span>=<span class="literal">False</span></span>):</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'{:0>2d}'</span>.<span class="built_in">format</span>(<span class="built_in">int</span>(data//<span class="number">3600</span>))+<span class="string">':'</span>+<span class="string">'{:0>2d}'</span>.<span class="built_in">format</span>((<span class="built_in">int</span>(data)%<span class="number">3600</span>)//<span class="number">60</span>)+<span class="string">':'</span>+<span class="string">'{:0>2d}'</span>.<span class="built_in">format</span>(<span class="built_in">int</span>(data)%<span class="number">60</span>)+(<span class="string">'.'</span>+<span class="string">'{:0>3d}'</span>.<span class="built_in">format</span>(<span class="built_in">int</span>((data%<span class="number">1</span>)*<span class="number">1000</span>)) <span class="keyword">if</span> <span class="keyword">not</span> <span class="built_in">round</span> <span class="keyword">else</span> <span class="string">''</span>)</span><br></pre></td></tr></table></figure><h2 id="计时控制"><a href="#计时控制" class="headerlink" title="计时控制"></a>计时控制</h2><p>刚刚我创建了三个按钮组件,现在在要对应地写着三个按钮被点击是执行的函数。</p><h3 id="开始和停止"><a href="#开始和停止" class="headerlink" title="开始和停止"></a>开始和停止</h3><p>这个函数可以控制<code>running</code>变量,以及做出对应的操作:</p><ul><li>设置按钮位置;</li><li>改变<code>timeDelta</code></li><li>设置按钮</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">startStop</span>():</span><br><span class="line"> <span class="keyword">global</span> running,startTimeStamp,lastEndStamp,timeDelta,lastRecordStamp</span><br><span class="line"> <span class="keyword">if</span> running:</span><br><span class="line"> lastEndStamp=time.time()</span><br><span class="line"> startStopButton.setText(<span class="string">'开始'</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">if</span> startTimeStamp==<span class="number">0</span>:</span><br><span class="line"> startTimeStamp=lastEndStamp=time.time()</span><br><span class="line"> timeDelta+=time.time()-lastEndStamp</span><br><span class="line"> startStopButton.setText(<span class="string">'停止'</span>)</span><br><span class="line"> recordButton.setDisabled(running)</span><br><span class="line"> running=<span class="keyword">not</span> running</span><br><span class="line"> clearButton.setDisabled(running)</span><br></pre></td></tr></table></figure><h3 id="记录"><a href="#记录" class="headerlink" title="记录"></a>记录</h3><p>记录按钮被按下时,就在表格中插入一行,第一列是次数,第二列是间隔,第三列是总计时间。最后,还要设置这次记录的时间戳,以计算这一次到下一次记录的时间间隔。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">writeRecord</span>():</span><br><span class="line"> <span class="keyword">global</span> lastRecordStamp</span><br><span class="line"> recordTable.insertRow(<span class="number">0</span>)</span><br><span class="line"> recordTable.setItem(<span class="number">0</span>,<span class="number">0</span>,QTableWidgetItem(<span class="built_in">str</span>(recordTable.rowCount())))</span><br><span class="line"> <span class="keyword">if</span> recordTable.rowCount()><span class="number">1</span>:</span><br><span class="line"> recordTable.setItem(<span class="number">0</span>,<span class="number">1</span>,QTableWidgetItem(formatTime(getTime()-lastRecordStamp)))</span><br><span class="line"> recordTable.setItem(<span class="number">0</span>,<span class="number">2</span>,QTableWidgetItem(formatTime(getTime())))</span><br><span class="line"> lastRecordStamp=getTime()</span><br></pre></td></tr></table></figure><h3 id="清除记录"><a href="#清除记录" class="headerlink" title="清除记录"></a>清除记录</h3><p>清除,要把各种变量都初始化,设置时间文本的文字也为初始的。因为表格控件没有提供清空函数,所以只能逐行删除直至表格为空为止。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">clearRecord</span>():</span><br><span class="line"> <span class="keyword">global</span> startTimeStamp,lastEndStamp,timeDelta,recorder</span><br><span class="line"> startTimeStamp=lastEndStamp=timeDelta=<span class="number">0</span></span><br><span class="line"> recorder.setText(<span class="string">'00:00:00.000'</span>)</span><br><span class="line"> clearButton.setDisabled(<span class="literal">True</span>)</span><br><span class="line"> <span class="keyword">while</span>(recordTable.rowCount()><span class="number">0</span>):</span><br><span class="line"> recordTable.removeRow(<span class="number">0</span>)</span><br></pre></td></tr></table></figure><h3 id="连接按钮与函数"><a href="#连接按钮与函数" class="headerlink" title="连接按钮与函数"></a>连接按钮与函数</h3><p>使用<code>按钮控件.clicked.connect(函数名)</code>就可以在按钮被点击时调用函数。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">startStopButton.clicked.connect(startStop) </span><br><span class="line">recordButton.clicked.connect(writeRecord) </span><br><span class="line">clearButton.clicked.connect(clearRecord)</span><br></pre></td></tr></table></figure><h2 id="更新显示-1"><a href="#更新显示-1" class="headerlink" title="更新显示"></a>更新显示</h2><p>窗口的自适应需要一些计算。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># def update():</span></span><br><span class="line"> <span class="keyword">global</span> startTimeStamp,timeDelta</span><br><span class="line"> <span class="comment"># size1_1=widgetslist[0].size()</span></span><br><span class="line"> <span class="comment"># nowtime=time.strftime('%H:%M:%S')</span></span><br><span class="line"> <span class="comment"># labelTime.setText(nowtime)</span></span><br><span class="line"> <span class="comment"># labelTime.move(size1_1.width()/2-size2.width()/2,size1_1.height()/2-size2.height()/2)</span></span><br><span class="line"> </span><br><span class="line"> size1_2=widgetslist[<span class="number">1</span>].size()</span><br><span class="line"> size2=labelTime.size()</span><br><span class="line"> size3=recorder.size()</span><br><span class="line"> size4=startStopButton.size()</span><br><span class="line"> size5=recordButton.size()</span><br><span class="line"> size6=clearButton.size()</span><br><span class="line"> recorder.move(size1_2.width()/<span class="number">2</span>-size3.width()/<span class="number">2</span>,<span class="number">10</span>)</span><br><span class="line"> startStopButton.move(size1_2.width()/<span class="number">2</span>-size5.width()/<span class="number">2</span>-<span class="number">10</span>-size4.width(),size1_2.height()-<span class="number">10</span>-size4.height())</span><br><span class="line"> recordButton.move(size1_2.width()/<span class="number">2</span>-size5.width()/<span class="number">2</span>,size1_2.height()-<span class="number">10</span>-size5.height())</span><br><span class="line"> clearButton.move(size1_2.width()/<span class="number">2</span>+size5.width()/<span class="number">2</span>+<span class="number">10</span>,size1_2.height()-<span class="number">10</span>-size6.height())</span><br><span class="line"> recordTable.resize(size1_2.width()-<span class="number">200</span>,size1_2.height()-<span class="number">320</span>)</span><br><span class="line"> size7=recordTable.size()</span><br><span class="line"> recordTable.move(size1_2.width()/<span class="number">2</span>-size7.width()/<span class="number">2</span>,<span class="number">220</span>)</span><br><span class="line"> recordTable.setColumnWidth(<span class="number">0</span>,<span class="number">40</span>)</span><br><span class="line"> recordTable.setColumnWidth(<span class="number">1</span>,size7.width()/<span class="number">2</span>-<span class="number">20</span>)</span><br><span class="line"> recordTable.setColumnWidth(<span class="number">2</span>,size7.width()/<span class="number">2</span>-<span class="number">20</span>)</span><br><span class="line"> <span class="keyword">if</span> running:</span><br><span class="line"> stampDelta=getTime()</span><br><span class="line"> rec=formatTime(stampDelta)</span><br><span class="line"> recorder.setText(rec)</span><br></pre></td></tr></table></figure><h2 id="效果-1"><a href="#效果-1" class="headerlink" title="效果"></a>效果</h2><p><img src="https://s1.imagehub.cc/images/2024/12/08/d5680b89d31cdccd2edf6412960c29e6.png" alt="image"></p><h1 id="倒计时"><a href="#倒计时" class="headerlink" title="倒计时"></a>倒计时</h1><p>倒计时不像正向计时那么简单,需要支持一些倒计时同时计时。这就需要建立一个倒计时类来完成这个任务。</p><h2 id="创建组件-1"><a href="#创建组件-1" class="headerlink" title="创建组件"></a>创建组件</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">newCountDown=QPushButton(<span class="string">'新建'</span>,widgetslist[<span class="number">2</span>])</span><br><span class="line">deleteCountDown=QPushButton(<span class="string">'编辑'</span>,widgetslist[<span class="number">2</span>])</span><br><span class="line">countDownScrollArea=QScrollArea(widgetslist[<span class="number">2</span>])</span><br><span class="line">countDownScrollArea.move(<span class="number">10</span>,<span class="number">30</span>)</span><br><span class="line">countDownScrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)</span><br><span class="line">countDownScrollAreaWidget=QWidget()</span><br><span class="line">countDownScrollArea.setWidget(countDownScrollAreaWidget)</span><br><span class="line">countDownList=[]</span><br></pre></td></tr></table></figure><p>还是一些按钮,但是多了一个滚动区,这样可以滚动显示倒计时控件。</p><h2 id="创建倒计时类"><a href="#创建倒计时类" class="headerlink" title="创建倒计时类"></a>创建倒计时类</h2><p>我将在<code>QtWidgets.QGroupBox</code>的基础上制作这个倒计时组件。</p><h3 id="实例化"><a href="#实例化" class="headerlink" title="实例化"></a>实例化</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CountDown</span>(<span class="title class_ inherited__">QGroupBox</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,parent,timelength,title,music</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__(parent)</span><br><span class="line"> <span class="variable language_">self</span>.timelength=timelength</span><br><span class="line"> <span class="variable language_">self</span>.titlestr=title</span><br><span class="line"> <span class="variable language_">self</span>.music=music</span><br><span class="line"> <span class="variable language_">self</span>.restTime=<span class="number">0</span></span><br><span class="line"> <span class="variable language_">self</span>.startTimeStamp=<span class="number">0</span></span><br><span class="line"> <span class="variable language_">self</span>.lastEndStamp=<span class="number">0</span></span><br><span class="line"> <span class="variable language_">self</span>.timeDelta=<span class="number">0</span></span><br><span class="line"> <span class="variable language_">self</span>.running=<span class="literal">False</span></span><br></pre></td></tr></table></figure><h3 id="启动"><a href="#启动" class="headerlink" title="启动"></a>启动</h3><p>实例化方法内不能穿件组件,所以单独建一个启动函数,在对象实例化之后使用。<br>按钮绑定的函数后续都会定义。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class CountDown(QGroupBox):</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">launch</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.resize(<span class="number">400</span>,<span class="number">300</span>)</span><br><span class="line"> <span class="variable language_">self</span>.restTime=<span class="variable language_">self</span>.timelength</span><br><span class="line"> <span class="variable language_">self</span>.timelabel=QLabel(formatTime(<span class="variable language_">self</span>.restTime),<span class="variable language_">self</span>)</span><br><span class="line"> font=QFont(<span class="string">'Arian'</span>,<span class="number">40</span>,<span class="number">10</span>)</span><br><span class="line"> <span class="variable language_">self</span>.timelabel.setFont(font)</span><br><span class="line"> <span class="variable language_">self</span>.progressbar=QProgressBar(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.progressbar.setTextVisible(<span class="literal">False</span>)</span><br><span class="line"> <span class="variable language_">self</span>.progressbar.setRange(<span class="number">0</span>,<span class="number">10000</span>)</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton=QPushButton(<span class="string">'开始'</span>,<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.clicked.connect(<span class="variable language_">self</span>.startStop)</span><br><span class="line"> <span class="variable language_">self</span>.clearButton=QPushButton(<span class="string">'还原'</span>,<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.clearButton.clicked.connect(<span class="variable language_">self</span>.reset)</span><br><span class="line"> <span class="variable language_">self</span>.clearButton.setDisabled(<span class="literal">True</span>)</span><br><span class="line"> <span class="variable language_">self</span>.editButton=<span class="literal">None</span></span><br><span class="line"> <span class="variable language_">self</span>.deleteButton=<span class="literal">None</span></span><br><span class="line"> <span class="variable language_">self</span>.mode=<span class="literal">True</span></span><br></pre></td></tr></table></figure><h3 id="其他函数"><a href="#其他函数" class="headerlink" title="其他函数"></a>其他函数</h3><p>包括:</p><ul><li>切换模式(开始与清除/编辑与删除)</li><li>开始停止</li><li>更新显示</li><li>清除</li><li>编辑</li><li>倒计时结束任务栏通知</li><li>删除</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class CountDown(QGroupBox)</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">toggleMode</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.mode:</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.hide()</span><br><span class="line"> <span class="variable language_">self</span>.clearButton.hide()</span><br><span class="line"> <span class="variable language_">self</span>.editButton=QPushButton(<span class="string">'编辑'</span>,<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.editButton.clicked.connect(<span class="variable language_">self</span>.edit)</span><br><span class="line"> <span class="variable language_">self</span>.editButton.show()</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton=QPushButton(<span class="string">'删除'</span>,<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton.clicked.connect(<span class="variable language_">self</span>.deleteSelf)</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton.show()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.show()</span><br><span class="line"> <span class="variable language_">self</span>.clearButton.show()</span><br><span class="line"> <span class="variable language_">self</span>.editButton.hide()</span><br><span class="line"> <span class="variable language_">self</span>.editButton=<span class="literal">None</span></span><br><span class="line"> <span class="variable language_">self</span>.deleteButton.hide()</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton=<span class="literal">None</span></span><br><span class="line"> <span class="variable language_">self</span>.mode=<span class="keyword">not</span> <span class="variable language_">self</span>.mode</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">updating</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.setTitle(<span class="variable language_">self</span>.titlestr)</span><br><span class="line"> selfsize=<span class="variable language_">self</span>.size()</span><br><span class="line"> buttonsize=<span class="variable language_">self</span>.startStopButton.size()</span><br><span class="line"> progressbarsize=<span class="variable language_">self</span>.progressbar.size()</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">abs</span>(<span class="variable language_">self</span>.timelength-<span class="built_in">max</span>(<span class="number">0</span>,time.time()-<span class="variable language_">self</span>.startTimeStamp-<span class="variable language_">self</span>.timeDelta))<<span class="number">0.0005</span>:</span><br><span class="line"> <span class="variable language_">self</span>.showMessage()</span><br><span class="line"> <span class="variable language_">self</span>.startStop()</span><br><span class="line"> <span class="variable language_">self</span>.timelabel.setText(<span class="string">'00:00:00:000'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.restTime=<span class="built_in">max</span>(<span class="number">0</span>,<span class="variable language_">self</span>.timelength-<span class="built_in">max</span>(<span class="number">0</span>,time.time()-<span class="variable language_">self</span>.startTimeStamp-<span class="variable language_">self</span>.timeDelta))</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.running:</span><br><span class="line"> <span class="variable language_">self</span>.timelabel.setText(formatTime(<span class="variable language_">self</span>.restTime))</span><br><span class="line"> <span class="variable language_">self</span>.progressbar.setValue(<span class="variable language_">self</span>.restTime/<span class="variable language_">self</span>.timelength*<span class="number">10000</span>)</span><br><span class="line"> <span class="variable language_">self</span>.progressbar.update()</span><br><span class="line"> labelsize=<span class="variable language_">self</span>.timelabel.size()</span><br><span class="line"> <span class="variable language_">self</span>.timelabel.move(selfsize.width()/<span class="number">2</span>-labelsize.width()/<span class="number">2</span>,selfsize.height()/<span class="number">2</span>-labelsize.height()/<span class="number">2</span>)</span><br><span class="line"> <span class="variable language_">self</span>.progressbar.resize(selfsize.width()-<span class="number">20</span>,<span class="number">20</span>)</span><br><span class="line"> <span class="variable language_">self</span>.progressbar.move(<span class="number">10</span>,selfsize.height()-<span class="number">10</span>-buttonsize.height()-<span class="number">10</span>-progressbarsize.height())</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.mode:</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.move(selfsize.width()/<span class="number">2</span>-<span class="number">5</span>-buttonsize.width(),selfsize.height()-<span class="number">10</span>-buttonsize.height())</span><br><span class="line"> <span class="variable language_">self</span>.clearButton.move(selfsize.width()/<span class="number">2</span>+<span class="number">5</span>,selfsize.height()-<span class="number">10</span>-buttonsize.height())</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="variable language_">self</span>.editButton.move(selfsize.width()/<span class="number">2</span>-<span class="number">5</span>-buttonsize.width(),selfsize.height()-<span class="number">10</span>-buttonsize.height())</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton.move(selfsize.width()/<span class="number">2</span>+<span class="number">5</span>,selfsize.height()-<span class="number">10</span>-buttonsize.height())</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">startStop</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.running:</span><br><span class="line"> <span class="variable language_">self</span>.lastEndStamp=time.time()</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.setText(<span class="string">'开始'</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.startTimeStamp==<span class="number">0</span>:</span><br><span class="line"> <span class="variable language_">self</span>.startTimeStamp=<span class="variable language_">self</span>.lastEndStamp=time.time()</span><br><span class="line"> <span class="variable language_">self</span>.timeDelta+=time.time()-<span class="variable language_">self</span>.lastEndStamp</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.setText(<span class="string">'停止'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.running=<span class="keyword">not</span> <span class="variable language_">self</span>.running</span><br><span class="line"> <span class="variable language_">self</span>.clearButton.setDisabled(<span class="variable language_">self</span>.running)</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">reset</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.startTimeStamp=<span class="variable language_">self</span>.lastEndStamp=<span class="variable language_">self</span>.timeDelta=<span class="number">0</span></span><br><span class="line"> <span class="variable language_">self</span>.timelabel.setText(formatTime(<span class="variable language_">self</span>.timelength))</span><br><span class="line"> <span class="variable language_">self</span>.clearButton.setDisabled(<span class="literal">True</span>)</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">self</span>):</span><br><span class="line"> editor=CountDownEdit(<span class="variable language_">self</span>.timelength,<span class="variable language_">self</span>.titlestr,<span class="variable language_">self</span>.music)</span><br><span class="line"> editor.editData()</span><br><span class="line"> <span class="variable language_">self</span>.timelength=editor.length</span><br><span class="line"> <span class="variable language_">self</span>.restTime=<span class="variable language_">self</span>.timelength</span><br><span class="line"> <span class="variable language_">self</span>.titlestr=editor.titlestr</span><br><span class="line"> <span class="variable language_">self</span>.music=editor.music</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">showMessage</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.trayicon=QSystemTrayIcon()</span><br><span class="line"> <span class="variable language_">self</span>.trayicon.setIcon(icon)</span><br><span class="line"> <span class="variable language_">self</span>.trayicon.show()</span><br><span class="line"> <span class="variable language_">self</span>.trayicon.showMessage(<span class="string">'计时器到了'</span>,<span class="string">'倒计时'</span>+<span class="variable language_">self</span>.titlestr+<span class="string">'计时已完成。'</span>,icon)</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">deleteSelf</span>(<span class="params">self</span>):</span><br><span class="line"> countDownList.remove(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.deleteLater()</span><br><span class="line"> <span class="keyword">del</span> <span class="variable language_">self</span></span><br></pre></td></tr></table></figure><h2 id="倒计时编辑类"><a href="#倒计时编辑类" class="headerlink" title="倒计时编辑类"></a>倒计时编辑类</h2><p>刚刚的<code>edit()</code>函数里,就有一个<code>CountDownEdit</code>。当用户编辑一个倒计时时,就要打开一个倒计时编辑窗口,因此,我单独再建一个类,打开一个<code>QtWidgets.QDialog</code>。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CountDownEdit</span>(<span class="title class_ inherited__">QDialog</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,length,title,music</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__()</span><br><span class="line"> <span class="variable language_">self</span>.confirmed=<span class="literal">False</span></span><br><span class="line"> <span class="variable language_">self</span>.length=length</span><br><span class="line"> <span class="variable language_">self</span>.titlestr=title</span><br><span class="line"> <span class="variable language_">self</span>.music=music</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">editData</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.setWindowTitle(<span class="string">'倒计时编辑'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.vlayout=QVBoxLayout()</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout=QGridLayout()</span><br><span class="line"> <span class="variable language_">self</span>.hlayout=QHBoxLayout()</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.setSpacing(<span class="number">10</span>)</span><br><span class="line"> <span class="variable language_">self</span>.label1=QLabel(<span class="string">'时长'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.label2=QLabel(<span class="string">'标题'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.label3=QLabel(<span class="string">'音乐'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1=QHBoxLayout()</span><br><span class="line"> <span class="variable language_">self</span>.content1_1=QSpinBox()</span><br><span class="line"> <span class="variable language_">self</span>.content1_1.setMinimum(<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_1.setMaximum(<span class="number">99</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_1.setValue(<span class="variable language_">self</span>.length//<span class="number">3600</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_2=QLabel(<span class="string">':'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_3=QSpinBox()</span><br><span class="line"> <span class="variable language_">self</span>.content1_3.setMinimum(<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_3.setMaximum(<span class="number">59</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_3.setValue((<span class="variable language_">self</span>.length%<span class="number">3600</span>)//<span class="number">60</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_4=QLabel(<span class="string">':'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_5=QSpinBox()</span><br><span class="line"> <span class="variable language_">self</span>.content1_5.setMinimum(<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_5.setMaximum(<span class="number">59</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_5.setValue(<span class="variable language_">self</span>.length%<span class="number">60</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_1)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_2)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_3)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_4)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_5)</span><br><span class="line"> <span class="variable language_">self</span>.content2=QLineEdit()</span><br><span class="line"> <span class="variable language_">self</span>.content2.setText(<span class="variable language_">self</span>.titlestr)</span><br><span class="line"> <span class="variable language_">self</span>.content3=QComboBox()</span><br><span class="line"> <span class="variable language_">self</span>.content3.addItems(musicNameList)</span><br><span class="line"> <span class="variable language_">self</span>.content3.setCurrentIndex(<span class="variable language_">self</span>.music)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.label1,<span class="number">0</span>,<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.label2,<span class="number">1</span>,<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.label3,<span class="number">2</span>,<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addLayout(<span class="variable language_">self</span>.content1,<span class="number">0</span>,<span class="number">1</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.content2,<span class="number">1</span>,<span class="number">1</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.content3,<span class="number">2</span>,<span class="number">1</span>)</span><br><span class="line"> <span class="variable language_">self</span>.confirm=QPushButton(<span class="string">'确定'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.cancel=QPushButton(<span class="string">'取消'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.confirm.clicked.connect(<span class="variable language_">self</span>.confirming)</span><br><span class="line"> <span class="variable language_">self</span>.cancel.clicked.connect(<span class="variable language_">self</span>.close)</span><br><span class="line"> <span class="variable language_">self</span>.hlayout.addWidget(<span class="variable language_">self</span>.confirm)</span><br><span class="line"> <span class="variable language_">self</span>.hlayout.addWidget(<span class="variable language_">self</span>.cancel)</span><br><span class="line"> <span class="variable language_">self</span>.vlayout.addLayout(<span class="variable language_">self</span>.gridlayout)</span><br><span class="line"> <span class="variable language_">self</span>.vlayout.addLayout(<span class="variable language_">self</span>.hlayout)</span><br><span class="line"> <span class="variable language_">self</span>.setLayout(<span class="variable language_">self</span>.vlayout)</span><br><span class="line"> <span class="variable language_">self</span>.show()</span><br><span class="line"> <span class="variable language_">self</span>.<span class="built_in">exec</span>()</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">confirming</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.confirmed=<span class="literal">True</span></span><br><span class="line"> <span class="variable language_">self</span>.length=<span class="variable language_">self</span>.content1_1.value()*<span class="number">3600</span>+<span class="variable language_">self</span>.content1_3.value()*<span class="number">60</span>+<span class="variable language_">self</span>.content1_5.value()</span><br><span class="line"> <span class="variable language_">self</span>.titlestr=<span class="variable language_">self</span>.content2.text()</span><br><span class="line"> <span class="variable language_">self</span>.music=<span class="variable language_">self</span>.content3.currentIndex()</span><br><span class="line"> <span class="variable language_">self</span>.close()</span><br></pre></td></tr></table></figure><h2 id="按钮绑定函数"><a href="#按钮绑定函数" class="headerlink" title="按钮绑定函数"></a>按钮绑定函数</h2><p>接着,给刚才两个按钮创建并绑定函数。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">onNewCountDown</span>():</span><br><span class="line"> <span class="keyword">global</span> countDownList</span><br><span class="line"> countDownEdit=CountDownEdit(<span class="number">0</span>,<span class="string">'未命名'</span>,<span class="number">0</span>)</span><br><span class="line"> countDownEdit.editData()</span><br><span class="line"> <span class="keyword">if</span> countDownEdit.confirmed:</span><br><span class="line"> countDown=CountDown(countDownScrollAreaWidget,countDownEdit.length,countDownEdit.titlestr,countDownEdit.music)</span><br><span class="line"> countDown.launch()</span><br><span class="line"> countDown.show()</span><br><span class="line"> countDownList.append(countDown)</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">onDeleteCountDown</span>():</span><br><span class="line"> <span class="keyword">global</span> countDownList</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> countDownList:</span><br><span class="line"> i.toggleMode()</span><br><span class="line">newCountDown.clicked.connect(onNewCountDown)</span><br><span class="line">deleteCountDown.clicked.connect(onDeleteCountDown)</span><br></pre></td></tr></table></figure><h2 id="更新显示-2"><a href="#更新显示-2" class="headerlink" title="更新显示"></a>更新显示</h2><p>没错,又要更新</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># def update():</span></span><br><span class="line">size1_3=widgetslist[<span class="number">2</span>].size()</span><br><span class="line"> size8=newCountDown.size()</span><br><span class="line"> size9=deleteCountDown.size()</span><br><span class="line"> newCountDown.move(size1_3.width()/<span class="number">2</span>-<span class="number">5</span>-size8.width(),size1_3.height()-<span class="number">10</span>-size8.height())</span><br><span class="line"> deleteCountDown.move(size1_3.width()/<span class="number">2</span>+<span class="number">5</span>,size1_3.height()-<span class="number">10</span>-size9.height())</span><br><span class="line"> countDownScrollArea.resize(size1_3.width()-<span class="number">20</span>,size1_3.height()-<span class="number">50</span>-size8.height())</span><br><span class="line"> size10=countDownScrollArea.size()</span><br><span class="line"> size11=QSize(<span class="number">400</span>,<span class="number">300</span>)</span><br><span class="line"> numPerRow=(size10.width()-size11.width())//(size11.width()+<span class="number">10</span>)+<span class="number">1</span></span><br><span class="line"> widthPerRow=numPerRow*size11.width()+(numPerRow-<span class="number">1</span>)*<span class="number">10</span></span><br><span class="line"> countDownScrollAreaWidget.resize(size10.width(),<span class="number">10</span>+((<span class="built_in">len</span>(countDownList))//numPerRow+<span class="number">1</span>)*(<span class="number">10</span>+size11.height()))</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(countDownList)):</span><br><span class="line"> countDownList[i].move(size10.width()/<span class="number">2</span>-widthPerRow/<span class="number">2</span>+(i%numPerRow)*(<span class="number">10</span>+size11.width()),<span class="number">10</span>+(i//numPerRow)*(<span class="number">10</span>+size11.height()))</span><br><span class="line"> countDownList[i].updating()</span><br></pre></td></tr></table></figure><h2 id="文件读写"><a href="#文件读写" class="headerlink" title="文件读写"></a>文件读写</h2><p>这个时钟应用还是支持保存和读取计时器的。实现就是文件读写。</p><h3 id="读入"><a href="#读入" class="headerlink" title="读入"></a>读入</h3><p>这个是程序每次打开就执行的。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># deleteCountDown.clicked.connect(onDeleteCountDown)</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">'../data/countdown.txt'</span>,<span class="string">'r'</span>,encoding=<span class="string">'utf-8'</span>) <span class="keyword">as</span> f:</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> f.readlines():</span><br><span class="line"> timelength,title,music=i.split(<span class="string">':/:'</span>)</span><br><span class="line"> countDown=CountDown(countDownScrollAreaWidget,<span class="built_in">int</span>(timelength),title,<span class="built_in">int</span>(music))</span><br><span class="line"> countDown.launch()</span><br><span class="line"> countDown.show()</span><br><span class="line"> countDownList.append(countDown)</span><br><span class="line"></span><br><span class="line"><span class="comment"># def update():</span></span><br></pre></td></tr></table></figure><h3 id="保存"><a href="#保存" class="headerlink" title="保存"></a>保存</h3><p>这个就是程序每次关闭执行的。<br>让我们回到程序一开始:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Window(QWidget):</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">closeEvent</span>(<span class="params">self,event</span>):</span><br><span class="line"> <span class="keyword">global</span> countDownList,alarmList</span><br><span class="line"> <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">'../data/countdown.txt'</span>,<span class="string">'w'</span>,encoding=<span class="string">'utf-8'</span>) <span class="keyword">as</span> f:</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> countDownList:</span><br><span class="line"> f.write(<span class="built_in">str</span>(i.timelength)+<span class="string">':/:'</span>+i.titlestr+<span class="string">':/:'</span>+<span class="built_in">str</span>(i.music)+<span class="string">'\n'</span>)</span><br></pre></td></tr></table></figure><h2 id="效果-2"><a href="#效果-2" class="headerlink" title="效果"></a>效果</h2><p><img src="https://s1.imagehub.cc/images/2024/12/08/62420788b13c81e6b3003003d2816649.png" alt="image"></p><h1 id="闹钟"><a href="#闹钟" class="headerlink" title="闹钟"></a>闹钟</h1><p>闹钟的程序,就是把倒计时复制了一遍改的,所以直接给个代码</p><h2 id="主要代码"><a href="#主要代码" class="headerlink" title="主要代码"></a>主要代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br></pre></td><td class="code"><pre><span class="line">newAlarm=QPushButton(<span class="string">'新建'</span>,widgetslist[<span class="number">3</span>])</span><br><span class="line">deleteAlarm=QPushButton(<span class="string">'编辑'</span>,widgetslist[<span class="number">3</span>])</span><br><span class="line">alarmScrollArea=QScrollArea(widgetslist[<span class="number">3</span>])</span><br><span class="line">alarmScrollArea.move(<span class="number">10</span>,<span class="number">30</span>)</span><br><span class="line">alarmScrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)</span><br><span class="line">alarmScrollAreaWidget=QWidget()</span><br><span class="line">alarmScrollArea.setWidget(alarmScrollAreaWidget)</span><br><span class="line">alarmList=[]</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Alarm</span>(<span class="title class_ inherited__">QGroupBox</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,parent,timelength,title,music,repeat,description,running</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__(parent)</span><br><span class="line"> <span class="variable language_">self</span>.timelength=timelength</span><br><span class="line"> <span class="variable language_">self</span>.titlestr=title</span><br><span class="line"> <span class="variable language_">self</span>.music=music</span><br><span class="line"> <span class="variable language_">self</span>.running=running</span><br><span class="line"> <span class="variable language_">self</span>.repeat=repeat</span><br><span class="line"> <span class="variable language_">self</span>.description=description</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">launch</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.resize(<span class="number">400</span>,<span class="number">300</span>)</span><br><span class="line"> <span class="variable language_">self</span>.restTime=<span class="variable language_">self</span>.timelength</span><br><span class="line"> <span class="variable language_">self</span>.timelabel=QLabel(formatTime(<span class="variable language_">self</span>.restTime,<span class="built_in">round</span>=<span class="literal">True</span>),<span class="variable language_">self</span>)</span><br><span class="line"> font=QFont(<span class="string">'Arian'</span>,<span class="number">40</span>,<span class="number">10</span>)</span><br><span class="line"> <span class="variable language_">self</span>.timelabel.setFont(font)</span><br><span class="line"> <span class="variable language_">self</span>.descriptionLabel=QLabel(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.descriptionLabel.setWordWrap(<span class="literal">True</span>)</span><br><span class="line"> <span class="variable language_">self</span>.descriptionLabel.setAlignment(Qt.AlignmentFlag.AlignTop|Qt.AlignmentFlag.AlignLeft)</span><br><span class="line"> <span class="variable language_">self</span>.repetitionLabel=QLabel(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton=QPushButton(<span class="string">'关闭'</span> <span class="keyword">if</span> <span class="variable language_">self</span>.running <span class="keyword">else</span> <span class="string">'开启'</span>,<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.clicked.connect(<span class="variable language_">self</span>.startStop)</span><br><span class="line"> <span class="variable language_">self</span>.editButton=<span class="literal">None</span></span><br><span class="line"> <span class="variable language_">self</span>.deleteButton=<span class="literal">None</span></span><br><span class="line"> <span class="variable language_">self</span>.mode=<span class="literal">True</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">toggleMode</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.mode:</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.hide()</span><br><span class="line"> <span class="variable language_">self</span>.editButton=QPushButton(<span class="string">'编辑'</span>,<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.editButton.clicked.connect(<span class="variable language_">self</span>.edit)</span><br><span class="line"> <span class="variable language_">self</span>.editButton.show()</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton=QPushButton(<span class="string">'删除'</span>,<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton.clicked.connect(<span class="variable language_">self</span>.deleteSelf)</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton.show()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.show()</span><br><span class="line"> <span class="variable language_">self</span>.editButton.hide()</span><br><span class="line"> <span class="variable language_">self</span>.editButton=<span class="literal">None</span></span><br><span class="line"> <span class="variable language_">self</span>.deleteButton.hide()</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton=<span class="literal">None</span></span><br><span class="line"> <span class="variable language_">self</span>.mode=<span class="keyword">not</span> <span class="variable language_">self</span>.mode</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">updating</span>(<span class="params">self</span>):</span><br><span class="line"> hours,minutes,seconds=<span class="built_in">list</span>(<span class="built_in">map</span>(<span class="built_in">int</span>,time.strftime(<span class="string">'%H %M %S'</span>).split()))</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">abs</span>(<span class="variable language_">self</span>.timelength-(hours*<span class="number">3600</span>+minutes*<span class="number">60</span>+seconds))<<span class="number">0.0005</span> <span class="keyword">and</span> <span class="variable language_">self</span>.running:</span><br><span class="line"> <span class="variable language_">self</span>.showMessage()</span><br><span class="line"> <span class="variable language_">self</span>.startStop()</span><br><span class="line"> <span class="variable language_">self</span>.setTitle(<span class="variable language_">self</span>.titlestr)</span><br><span class="line"> selfsize=<span class="variable language_">self</span>.size()</span><br><span class="line"> buttonsize=<span class="variable language_">self</span>.startStopButton.size()</span><br><span class="line"> <span class="variable language_">self</span>.timelabel.setText(formatTime(<span class="variable language_">self</span>.timelength,<span class="built_in">round</span>=<span class="literal">True</span>))</span><br><span class="line"> labelsize=<span class="variable language_">self</span>.timelabel.size()</span><br><span class="line"> <span class="variable language_">self</span>.timelabel.move(selfsize.width()/<span class="number">2</span>-labelsize.width()/<span class="number">2</span>,<span class="number">30</span>)</span><br><span class="line"></span><br><span class="line"> <span class="variable language_">self</span>.descriptionLabel.setText(<span class="variable language_">self</span>.description)</span><br><span class="line"> <span class="variable language_">self</span>.descriptionLabel.setFixedSize(selfsize.width()-<span class="number">10</span>,<span class="number">200</span>)</span><br><span class="line"> labelsize=<span class="variable language_">self</span>.descriptionLabel.size()</span><br><span class="line"> <span class="variable language_">self</span>.descriptionLabel.move(selfsize.width()/<span class="number">2</span>-labelsize.width()/<span class="number">2</span>,<span class="number">150</span>)</span><br><span class="line"> text=[<span class="string">'星期一'</span>,<span class="string">'星期二'</span>,<span class="string">'星期三'</span>,<span class="string">'星期四'</span>,<span class="string">'星期五'</span>,<span class="string">'星期六'</span>,<span class="string">'星期日'</span>]</span><br><span class="line"> list1=[]</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">7</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.repeat[i]:</span><br><span class="line"> list1.append(text[i])</span><br><span class="line"> <span class="variable language_">self</span>.repetitionLabel.setText(<span class="string">','</span>.join(list1))</span><br><span class="line"> <span class="variable language_">self</span>.repetitionLabel.setFixedSize(selfsize.width()-<span class="number">10</span>,<span class="number">20</span>)</span><br><span class="line"> labelsize=<span class="variable language_">self</span>.repetitionLabel.size()</span><br><span class="line"> <span class="variable language_">self</span>.repetitionLabel.move(selfsize.width()/<span class="number">2</span>-labelsize.width()/<span class="number">2</span>,<span class="number">100</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.mode:</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.move(selfsize.width()/<span class="number">2</span>-buttonsize.width()/<span class="number">2</span>,selfsize.height()-<span class="number">10</span>-buttonsize.height())</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="variable language_">self</span>.editButton.move(selfsize.width()/<span class="number">2</span>-<span class="number">5</span>-buttonsize.width(),selfsize.height()-<span class="number">10</span>-buttonsize.height())</span><br><span class="line"> <span class="variable language_">self</span>.deleteButton.move(selfsize.width()/<span class="number">2</span>+<span class="number">5</span>,selfsize.height()-<span class="number">10</span>-buttonsize.height())</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">startStop</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.running:</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.setText(<span class="string">'开启'</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="variable language_">self</span>.startStopButton.setText(<span class="string">'关闭'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.running=<span class="keyword">not</span> <span class="variable language_">self</span>.running</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">self</span>):</span><br><span class="line"> editor=AlarmEdit(<span class="variable language_">self</span>.timelength,<span class="variable language_">self</span>.titlestr,<span class="variable language_">self</span>.music,<span class="variable language_">self</span>.repeat,<span class="variable language_">self</span>.description,<span class="variable language_">self</span>.running)</span><br><span class="line"> editor.editData()</span><br><span class="line"> <span class="variable language_">self</span>.timelength=editor.length</span><br><span class="line"> <span class="variable language_">self</span>.restTime=<span class="variable language_">self</span>.timelength</span><br><span class="line"> <span class="variable language_">self</span>.titlestr=editor.titlestr</span><br><span class="line"> <span class="variable language_">self</span>.music=editor.music</span><br><span class="line"> <span class="variable language_">self</span>.repeat=editor.repeat</span><br><span class="line"> <span class="variable language_">self</span>.description=editor.description</span><br><span class="line"> <span class="variable language_">self</span>.running=editor.running</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">showMessage</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.trayicon=QSystemTrayIcon()</span><br><span class="line"> <span class="variable language_">self</span>.trayicon.setIcon(icon)</span><br><span class="line"> <span class="variable language_">self</span>.trayicon.show()</span><br><span class="line"> <span class="variable language_">self</span>.trayicon.showMessage(<span class="string">'闹钟'</span>+formatTime(<span class="variable language_">self</span>.timelength,<span class="built_in">round</span>=<span class="literal">True</span>),<span class="variable language_">self</span>.description,icon)</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">deleteSelf</span>(<span class="params">self</span>):</span><br><span class="line"> alarmList.remove(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.deleteLater()</span><br><span class="line"> <span class="keyword">del</span> <span class="variable language_">self</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">AlarmEdit</span>(<span class="title class_ inherited__">QDialog</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,length,title,music,repeat,description,running</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__()</span><br><span class="line"> <span class="variable language_">self</span>.confirmed=<span class="literal">False</span></span><br><span class="line"> <span class="variable language_">self</span>.length=length</span><br><span class="line"> <span class="variable language_">self</span>.titlestr=title</span><br><span class="line"> <span class="variable language_">self</span>.music=music</span><br><span class="line"> <span class="variable language_">self</span>.repeat=repeat</span><br><span class="line"> <span class="variable language_">self</span>.description=description</span><br><span class="line"> <span class="variable language_">self</span>.running=running</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">editData</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.setWindowTitle(<span class="string">'闹钟编辑'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.vlayout=QVBoxLayout()</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout=QGridLayout()</span><br><span class="line"> <span class="variable language_">self</span>.hlayout=QHBoxLayout()</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.setSpacing(<span class="number">10</span>)</span><br><span class="line"> <span class="variable language_">self</span>.label1=QLabel(<span class="string">'时间'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.label2=QLabel(<span class="string">'标题'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.label3=QLabel(<span class="string">'音乐'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.label4=QLabel(<span class="string">'描述'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.label5=QLabel(<span class="string">'重复'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1=QHBoxLayout()</span><br><span class="line"> <span class="variable language_">self</span>.content1_1=QSpinBox()</span><br><span class="line"> <span class="variable language_">self</span>.content1_1.setMinimum(<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_1.setMaximum(<span class="number">23</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_1.setValue(<span class="variable language_">self</span>.length//<span class="number">3600</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_2=QLabel(<span class="string">':'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_3=QSpinBox()</span><br><span class="line"> <span class="variable language_">self</span>.content1_3.setMinimum(<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_3.setMaximum(<span class="number">59</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_3.setValue((<span class="variable language_">self</span>.length%<span class="number">3600</span>)//<span class="number">60</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_4=QLabel(<span class="string">':'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_5=QSpinBox()</span><br><span class="line"> <span class="variable language_">self</span>.content1_5.setMinimum(<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_5.setMaximum(<span class="number">59</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1_5.setValue(<span class="variable language_">self</span>.length%<span class="number">60</span>)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_1)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_2)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_3)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_4)</span><br><span class="line"> <span class="variable language_">self</span>.content1.addWidget(<span class="variable language_">self</span>.content1_5)</span><br><span class="line"> <span class="variable language_">self</span>.content2=QLineEdit()</span><br><span class="line"> <span class="variable language_">self</span>.content2.setText(<span class="variable language_">self</span>.titlestr)</span><br><span class="line"> <span class="variable language_">self</span>.content3=QComboBox()</span><br><span class="line"> <span class="variable language_">self</span>.content3.addItems(musicNameList)</span><br><span class="line"> <span class="variable language_">self</span>.content3.setCurrentIndex(<span class="variable language_">self</span>.music)</span><br><span class="line"> <span class="variable language_">self</span>.content4=QLineEdit()</span><br><span class="line"> <span class="variable language_">self</span>.content4.setText(<span class="variable language_">self</span>.description)</span><br><span class="line"> <span class="variable language_">self</span>.content5=QVBoxLayout()</span><br><span class="line"> text=[<span class="string">'星期一'</span>,<span class="string">'星期二'</span>,<span class="string">'星期三'</span>,<span class="string">'星期四'</span>,<span class="string">'星期五'</span>,<span class="string">'星期六'</span>,<span class="string">'星期日'</span>]</span><br><span class="line"> <span class="variable language_">self</span>.content5s=[QCheckBox(text=i) <span class="keyword">for</span> i <span class="keyword">in</span> text]</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="variable language_">self</span>.content5s:</span><br><span class="line"> <span class="variable language_">self</span>.content5.addWidget(i)</span><br><span class="line"> p=<span class="variable language_">self</span>.content5s.index(i)</span><br><span class="line"> i.setChecked(<span class="variable language_">self</span>.repeat[p])</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.label1,<span class="number">0</span>,<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.label2,<span class="number">1</span>,<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.label3,<span class="number">2</span>,<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.label4,<span class="number">3</span>,<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.label5,<span class="number">4</span>,<span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addLayout(<span class="variable language_">self</span>.content1,<span class="number">0</span>,<span class="number">1</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.content2,<span class="number">1</span>,<span class="number">1</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.content3,<span class="number">2</span>,<span class="number">1</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addWidget(<span class="variable language_">self</span>.content4,<span class="number">3</span>,<span class="number">1</span>)</span><br><span class="line"> <span class="variable language_">self</span>.gridlayout.addLayout(<span class="variable language_">self</span>.content5,<span class="number">4</span>,<span class="number">1</span>)</span><br><span class="line"> <span class="variable language_">self</span>.confirm=QPushButton(<span class="string">'确定'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.cancel=QPushButton(<span class="string">'取消'</span>)</span><br><span class="line"> <span class="variable language_">self</span>.confirm.clicked.connect(<span class="variable language_">self</span>.confirming)</span><br><span class="line"> <span class="variable language_">self</span>.cancel.clicked.connect(<span class="variable language_">self</span>.close)</span><br><span class="line"> <span class="variable language_">self</span>.hlayout.addWidget(<span class="variable language_">self</span>.confirm)</span><br><span class="line"> <span class="variable language_">self</span>.hlayout.addWidget(<span class="variable language_">self</span>.cancel)</span><br><span class="line"> <span class="variable language_">self</span>.vlayout.addLayout(<span class="variable language_">self</span>.gridlayout)</span><br><span class="line"> <span class="variable language_">self</span>.vlayout.addLayout(<span class="variable language_">self</span>.hlayout)</span><br><span class="line"> <span class="variable language_">self</span>.setLayout(<span class="variable language_">self</span>.vlayout)</span><br><span class="line"> <span class="variable language_">self</span>.show()</span><br><span class="line"> <span class="variable language_">self</span>.<span class="built_in">exec</span>()</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">setRepeat</span>(<span class="params">self,p</span>):</span><br><span class="line"> <span class="variable language_">self</span>.repeat[p]=<span class="keyword">not</span> <span class="variable language_">self</span>.repeat[p]</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">confirming</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.confirmed=<span class="literal">True</span></span><br><span class="line"> <span class="variable language_">self</span>.length=<span class="variable language_">self</span>.content1_1.value()*<span class="number">3600</span>+<span class="variable language_">self</span>.content1_3.value()*<span class="number">60</span>+<span class="variable language_">self</span>.content1_5.value()</span><br><span class="line"> <span class="variable language_">self</span>.titlestr=<span class="variable language_">self</span>.content2.text()</span><br><span class="line"> <span class="variable language_">self</span>.music=<span class="variable language_">self</span>.content3.currentIndex()</span><br><span class="line"> <span class="variable language_">self</span>.description=<span class="variable language_">self</span>.content4.text()</span><br><span class="line"> <span class="variable language_">self</span>.repeat=[i.isChecked() <span class="keyword">for</span> i <span class="keyword">in</span> <span class="variable language_">self</span>.content5s]</span><br><span class="line"> <span class="variable language_">self</span>.close()</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">onNewAlarm</span>():</span><br><span class="line"> <span class="keyword">global</span> alarmList</span><br><span class="line"> alarmEdit=AlarmEdit(<span class="number">0</span>,<span class="string">'未命名'</span>,<span class="number">0</span>,[<span class="literal">False</span>,<span class="literal">False</span>,<span class="literal">False</span>,<span class="literal">False</span>,<span class="literal">False</span>,<span class="literal">False</span>,<span class="literal">False</span>],<span class="string">''</span>,<span class="literal">True</span>)</span><br><span class="line"> alarmEdit.editData()</span><br><span class="line"> <span class="keyword">if</span> alarmEdit.confirmed:</span><br><span class="line"> alarm=Alarm(alarmScrollAreaWidget,alarmEdit.length,alarmEdit.titlestr,alarmEdit.music,alarmEdit.repeat,alarmEdit.description,alarmEdit.running)</span><br><span class="line"> alarm.launch()</span><br><span class="line"> alarm.show()</span><br><span class="line"> alarmList.append(alarm)</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">onDeleteAlarm</span>():</span><br><span class="line"> <span class="keyword">global</span> alarmList</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> alarmList:</span><br><span class="line"> i.toggleMode()</span><br><span class="line">newAlarm.clicked.connect(onNewAlarm)</span><br><span class="line">deleteAlarm.clicked.connect(onDeleteAlarm)</span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">'../data/alarm.txt'</span>,<span class="string">'r'</span>,encoding=<span class="string">'utf-8'</span>) <span class="keyword">as</span> f:</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> f.readlines():</span><br><span class="line"> timelength,title,music,repeat1,repeat2,repeat3,repeat4,repeat5,repeat6,repeat7,description,running1=i.split(<span class="string">':/:'</span>)</span><br><span class="line"> alarm=Alarm(alarmScrollAreaWidget,<span class="built_in">int</span>(timelength),title,<span class="built_in">int</span>(music),<span class="built_in">list</span>(<span class="built_in">map</span>(<span class="built_in">bool</span>,<span class="built_in">map</span>(<span class="built_in">int</span>,[repeat1,repeat2,repeat3,repeat4,repeat5,repeat6,repeat7]))),description,<span class="built_in">bool</span>(<span class="built_in">int</span>(running1)))</span><br><span class="line"> alarm.launch()</span><br><span class="line"> alarm.show()</span><br><span class="line"> alarmList.append(alarm)</span><br></pre></td></tr></table></figure><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>别忘了还需要更新显示,关闭时的文件写入</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># update():</span></span><br><span class="line"> size8=newAlarm.size()</span><br><span class="line"> size9=deleteAlarm.size()</span><br><span class="line"> newAlarm.move(size1_3.width()/<span class="number">2</span>-<span class="number">5</span>-size8.width(),size1_3.height()-<span class="number">10</span>-size8.height())</span><br><span class="line"> deleteAlarm.move(size1_3.width()/<span class="number">2</span>+<span class="number">5</span>,size1_3.height()-<span class="number">10</span>-size9.height())</span><br><span class="line"> alarmScrollArea.resize(size1_3.width()-<span class="number">20</span>,size1_3.height()-<span class="number">50</span>-size8.height())</span><br><span class="line"> size10=alarmScrollArea.size()</span><br><span class="line"> size11=QSize(<span class="number">400</span>,<span class="number">300</span>)</span><br><span class="line"> numPerRow=(size10.width()-size11.width())//(size11.width()+<span class="number">10</span>)+<span class="number">1</span></span><br><span class="line"> widthPerRow=numPerRow*size11.width()+(numPerRow-<span class="number">1</span>)*<span class="number">10</span></span><br><span class="line"> alarmScrollAreaWidget.resize(size10.width(),<span class="number">10</span>+((<span class="built_in">len</span>(alarmList))//numPerRow+<span class="number">1</span>)*(<span class="number">10</span>+size11.height()))</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(alarmList)):</span><br><span class="line"> alarmList[i].move(size10.width()/<span class="number">2</span>-widthPerRow/<span class="number">2</span>+(i%numPerRow)*(<span class="number">10</span>+size11.width()),<span class="number">10</span>+(i//numPerRow)*(<span class="number">10</span>+size11.height()))</span><br><span class="line"> alarmList[i].updating()</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Window(QWidget):</span></span><br><span class="line"><span class="comment"># def closeEvent(self,event):</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">'../data/alarm.txt'</span>,<span class="string">'w'</span>,encoding=<span class="string">'utf-8'</span>) <span class="keyword">as</span> f:</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> alarmList:</span><br><span class="line"> f.write(<span class="built_in">str</span>(i.timelength)+<span class="string">':/:'</span>+i.titlestr+<span class="string">':/:'</span>+<span class="built_in">str</span>(i.music)+<span class="string">':/:'</span>+<span class="string">':/:'</span>.join(<span class="built_in">map</span>(<span class="built_in">str</span>,<span class="built_in">map</span>(<span class="built_in">int</span>,i.repeat)))+<span class="string">':/:'</span>+i.description+<span class="string">':/:'</span>+<span class="built_in">str</span>(<span class="built_in">int</span>(i.running))+<span class="string">'\n'</span>)</span><br></pre></td></tr></table></figure><h2 id="效果-3"><a href="#效果-3" class="headerlink" title="效果"></a>效果</h2><p><img src="https://s1.imagehub.cc/images/2024/12/08/8d9a81c4e9e72270e372cba66f1ba9ba.png" alt="image"></p><h1 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h1><p>这个项目,虽然简单,但是代码有亿点点多。所以写这篇文章也写了很多。希望这个项目可以对学习Qt的小伙伴起到一些引导性作用。<br>其实,写这么长真的很不容易。<br>拜拜!See you next time!</p>]]></content>
<summary type="html"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>我使用Qt制作了一个时钟应用,现在来分享一下实现的过程。</p>
<p>这个小项目包括了四个部分:</p>
<ul>
<li>时钟(显示当前时间)</li>
<li>秒表(正向计时器,支持记录时间)</li>
<li>倒计时</li>
<li>闹钟</li>
</summary>
<category term="Qt" scheme="https://blog.qyadbr.top/categories/Qt/"/>
<category term="应用程序" scheme="https://blog.qyadbr.top/tags/%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F/"/>
<category term="简易" scheme="https://blog.qyadbr.top/tags/%E7%AE%80%E6%98%93/"/>
</entry>
<entry>
<title>自己动手写三维引擎(一)</title>
<link href="https://blog.qyadbr.top/posts/hexo8/"/>
<id>https://blog.qyadbr.top/posts/hexo8/</id>
<published>2024-11-24T10:43:25.000Z</published>
<updated>2025-05-28T13:02:51.937Z</updated>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近比较忙,所以很久没更新。</p><p>之前玩过很多三维沙盒游戏,但是很好奇是如何实现那种三维投射的</p><p>于是最近写出来了一个三维引擎</p><h1 id="过程"><a href="#过程" class="headerlink" title="过程"></a>过程</h1><p>我还是用的qt(自从用qt就发现爱上qt了)去实现打开窗口、画线等功能,但是qt自带的三维支持我不用。</p><h2 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h2><p>导入库、创建qt应用、创建空间对象,都不多说。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PySide6.QtWidgets <span class="keyword">import</span> QWidget,QApplication</span><br><span class="line"><span class="keyword">from</span> PySide6.QtGui <span class="keyword">import</span> QPainter,QColor,QPen,QCursor</span><br><span class="line"><span class="keyword">from</span> PySide6.QtCore <span class="keyword">import</span> QTimer,Qt</span><br><span class="line"><span class="keyword">import</span> math</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Space</span>():</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.objects=[]</span><br><span class="line">qapp=QApplication([])</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">run</span>():</span><br><span class="line"> qapp.<span class="built_in">exec</span>()</span><br></pre></td></tr></table></figure><h2 id="点对象和相机对象"><a href="#点对象和相机对象" class="headerlink" title="点对象和相机对象"></a>点对象和相机对象</h2><p>组成图形的基本元素是点。为了方便描述三维空间坐标,我创建了一个点对象。<br>同时,需要一个相机,点会投射到相机上</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Point</span>():</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,x,y,z</span>):</span><br><span class="line"> <span class="variable language_">self</span>.x=x</span><br><span class="line"> <span class="variable language_">self</span>.y=y</span><br><span class="line"> <span class="variable language_">self</span>.z=z</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Camera</span>(<span class="title class_ inherited__">QWidget</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,space,wwidth,wheight,caption,cwidth,cheight,cdeepth</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__()</span><br><span class="line"> <span class="variable language_">self</span>.resize(wwidth,wheight)<span class="comment">#窗口宽高</span></span><br><span class="line"> <span class="variable language_">self</span>.setWindowTitle(caption)<span class="comment">#窗口标题</span></span><br><span class="line"> <span class="variable language_">self</span>.space=space <span class="comment">#相机所在的空间</span></span><br><span class="line"> <span class="variable language_">self</span>.movement=[<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>] <span class="comment">#相机试试移动方向</span></span><br><span class="line"> <span class="variable language_">self</span>.rotatex=<span class="number">0</span></span><br><span class="line"> <span class="variable language_">self</span>.rotatey=<span class="number">90</span></span><br><span class="line"> <span class="variable language_">self</span>.rotatez=<span class="number">0</span> <span class="comment">#相机旋转角度</span></span><br><span class="line"> <span class="variable language_">self</span>.posx=<span class="number">0</span></span><br><span class="line"> <span class="variable language_">self</span>.posy=<span class="number">0</span> </span><br><span class="line"> <span class="variable language_">self</span>.posz=<span class="number">0</span> <span class="comment">#相机的位置</span></span><br><span class="line"> <span class="variable language_">self</span>.controled=<span class="literal">True</span> <span class="comment">#鼠标是否控制</span></span><br><span class="line"> <span class="variable language_">self</span>.movespeed=<span class="number">1</span> <span class="comment">#移速</span></span><br><span class="line"> <span class="variable language_">self</span>.setCursor(Qt.CursorShape.BlankCursor)</span><br><span class="line"> <span class="variable language_">self</span>.objects2D=[]</span><br><span class="line"> <span class="variable language_">self</span>.cwidth=cwidth </span><br><span class="line"> <span class="variable language_">self</span>.cheight=cheight <span class="comment">#相机宽高</span></span><br><span class="line"> <span class="variable language_">self</span>.cdeepth=cdeepth <span class="comment">#相机视锥深度</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">launch</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.timer=QTimer()</span><br><span class="line"> <span class="variable language_">self</span>.timer.start(<span class="number">5</span>)</span><br><span class="line"> <span class="variable language_">self</span>.timer.timeout.connect(<span class="variable language_">self</span>.update)</span><br><span class="line"> <span class="variable language_">self</span>.show()</span><br></pre></td></tr></table></figure><h3 id="投射"><a href="#投射" class="headerlink" title="投射"></a>投射</h3><p>这是整个三维投影中最关键的一点。</p><p><img src="https://s1.imagehub.cc/images/2024/11/24/aedd57047163cacfb51e36e33511af97.png" alt=""></p><p>可见,$\triangle OAE \sim \triangle OFD$, $OA$是相机深度,D是我们要投射的点 ,O是相机的位置,求出BE就可以求出E点的位置,即显示在屏幕上的位置。</p><p>从上面看(x坐标)和从右边看(y坐标)这张图都适用。</p><p>但是要考虑相机会旋转角度的问题。不妨将相机到投射的点看作一个向量。</p><p>假设相机位置为$(a<em>{x},a</em>{y},a<em>{z})$,投射的点的位置为$(c</em>{x},c<em>{y},c</em>{z})$,相机长$w$,宽$h$,深$d$</p><p>先计算向量旋转后的新向量:</p><script type="math/tex; mode=display">\begin{bmatrix}d_{x} \\d_{y} \\ d_{z}\end{bmatrix}=\begin{bmatrix} 1 & 0 & 0 \\0 & \cos (\theta_{x}) &\sin(\theta_{x}) \\0 & -\sin(\theta_{x})& \cos(\theta_{x})\end{bmatrix} \begin{bmatrix}\cos(\theta_{y}) &0 & -\sin(\theta_{y}) \\0 & 1& 0 \\\sin(\theta_{y})& 0 & \cos(\theta_{y})\end{bmatrix}\begin{bmatrix} \cos(\theta_{z})&\sin(\theta_{z})& 0 \\-\sin(\theta_{z})&\cos(\theta_{z})&0 \\0&0&1\end{bmatrix}\begin{bmatrix}a_{x}-c_{x} \\a_{y}-c_{y} \\a_{z}-c_{z}\end{bmatrix}</script><p>利用相似三角形对应边成比例,得:</p><script type="math/tex; mode=display">x=\frac{w}{2}-\frac{d}{d_{z}}d_{x}</script><script type="math/tex; mode=display">y=\frac{h}{2}-\frac{d}{d_{z}}d_{y}</script><p>因此我们有了代码:<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Point():</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">project</span>(<span class="params">self,camera</span>):</span><br><span class="line"> cx, cy, cz = camera.posx, camera.posy, camera.posz</span><br><span class="line"> thx, thy, thz = -camera.rotatex, camera.rotatey, camera.rotatez</span><br><span class="line"> x = <span class="variable language_">self</span>.x - cx</span><br><span class="line"> y = <span class="variable language_">self</span>.y - cy</span><br><span class="line"> z = <span class="variable language_">self</span>.z - cz</span><br><span class="line"> dx = math.cos(thy)*(math.sin(thz)*y+math.cos(thz)*x)-math.sin(thy)*z</span><br><span class="line"> dy = math.sin(thx)*(math.cos(thy)*z+math.sin(thy)*(math.sin(thz)*y+math.cos(thz)*x))+\</span><br><span class="line"> math.cos(thx)*(math.cos(thz)*y-math.sin(thz)*x)</span><br><span class="line"> dz = math.cos(thx)*(math.cos(thy)*z+math.sin(thy)*(math.sin(thz)*y+math.cos(thz)*x))-\</span><br><span class="line"> math.sin(thx)*(math.cos(thz)*y-math.sin(thz)*x)</span><br><span class="line"> newx= camera.cwidth/<span class="number">2</span>-(camera.cdeepth/dz) * dx</span><br><span class="line"> newy= camera.cheight/<span class="number">2</span>-(camera.cdeepth/dz) * dy </span><br><span class="line"> <span class="keyword">if</span> camera.width()/camera.height()>camera.cwidth/camera.cheight:</span><br><span class="line"> rectw=camera.height()/camera.cheight*camera.cwidth</span><br><span class="line"> resultx=camera.width()/<span class="number">2</span>-rectw/<span class="number">2</span>+newx/camera.cwidth*rectw</span><br><span class="line"> resulty=newy/camera.cheight*camera.height()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> recth=camera.width()/camera.cwidth*camera.cheight</span><br><span class="line"> resultx=newx/camera.cwidth*camera.width()</span><br><span class="line"> resulty=camera.height()/<span class="number">2</span>-recth/<span class="number">2</span>+newy/camera.cheight*recth</span><br><span class="line"> <span class="keyword">return</span> resultx,resulty,dz><span class="number">0</span><span class="comment">#当dz<=0时,即投影的点在相机的后面时,投射的位置不正确,需要特判处理</span></span><br></pre></td></tr></table></figure></p><h2 id="线段"><a href="#线段" class="headerlink" title="线段"></a>线段</h2><p>连接两个点的是线段。将一个线段投影之后线段还是直的,所以只需连接两个投影后的端点即可得到投影后的线段。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Segment</span>():</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,point1,point2</span>):</span><br><span class="line"> <span class="variable language_">self</span>.point1=point1</span><br><span class="line"> <span class="variable language_">self</span>.point2=point2</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">paint</span>(<span class="params">self,camera</span>):</span><br><span class="line"> x1,y1,m1=<span class="variable language_">self</span>.point1.project(camera)</span><br><span class="line"> x2,y2,m2=<span class="variable language_">self</span>.point2.project(camera)</span><br><span class="line"> <span class="keyword">if</span> m1><span class="number">0</span> <span class="keyword">and</span> m2><span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> x1,y1,x2,y2</span><br><span class="line"> <span class="keyword">elif</span> m1><span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> x1,y1,<span class="number">2</span>*x1-x2,<span class="number">2</span>*y1-y2</span><br><span class="line"> <span class="keyword">elif</span> m2><span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">2</span>*x2-x1,<span class="number">2</span>*y2-y1,x2,y2 <span class="comment">#这两都是将投影错误的端点绕着正确的端点旋转180度,即中心对称</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>,-<span class="number">1</span>,-<span class="number">1</span>,-<span class="number">1</span> <span class="comment">#当两个端点都在后面,说明这条线段在摄像机后面,因此不用显示</span></span><br></pre></td></tr></table></figure><h2 id="相机的控制"><a href="#相机的控制" class="headerlink" title="相机的控制"></a>相机的控制</h2><h4 id="监听键盘"><a href="#监听键盘" class="headerlink" title="监听键盘"></a>监听键盘</h4><p>用WSAD键移动,反引号键(Esc下面那个)呼出呼入鼠标。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Camera(QWidget):</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">keyPressEvent</span>(<span class="params">self, event</span>):</span><br><span class="line"> <span class="keyword">if</span> event.key()==Qt.Key.Key_W:</span><br><span class="line"> <span class="variable language_">self</span>.movement[<span class="number">0</span>]=<span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> event.key()==Qt.Key.Key_S:</span><br><span class="line"> <span class="variable language_">self</span>.movement[<span class="number">0</span>]=-<span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> event.key()==Qt.Key.Key_A:</span><br><span class="line"> <span class="variable language_">self</span>.movement[<span class="number">2</span>]=<span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> event.key()==Qt.Key.Key_D:</span><br><span class="line"> <span class="variable language_">self</span>.movement[<span class="number">2</span>]=-<span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> event.key()==Qt.Key.Key_Space:</span><br><span class="line"> <span class="variable language_">self</span>.movement[<span class="number">1</span>]=<span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> event.key()==Qt.Key.Key_Shift:</span><br><span class="line"> <span class="variable language_">self</span>.movement[<span class="number">1</span>]=-<span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> event.key()==Qt.Key.Key_QuoteLeft:</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.controled:</span><br><span class="line"> <span class="variable language_">self</span>.setCursor(Qt.CursorShape.ArrowCursor)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="variable language_">self</span>.setCursor(Qt.CursorShape.BlankCursor)</span><br><span class="line"> <span class="variable language_">self</span>.controled=<span class="keyword">not</span> <span class="variable language_">self</span>.controled</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">keyReleaseEvent</span>(<span class="params">self,event</span>):</span><br><span class="line"> <span class="variable language_">self</span>.movement=[<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>]</span><br></pre></td></tr></table></figure><h4 id="进行移动和旋转操作"><a href="#进行移动和旋转操作" class="headerlink" title="进行移动和旋转操作"></a>进行移动和旋转操作</h4><p>刚刚已经改变了<code>self.movement</code>的值,现在只需要根据值来移动相机,如果鼠标已锁住,同时用鼠标到窗口正中心的偏移来旋转相机,然后把鼠标的位置设置到画面正中心。</p><p>当<code>QWidget.update()</code>被执行时,就会执行<code>paintEvent()</code>,重写这个函数就可以实现重复执行。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Camera(QWidget):</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">paintEvent</span>(<span class="params">self,event</span>):</span><br><span class="line"> <span class="variable language_">self</span>.posx+= <span class="variable language_">self</span>.movement[<span class="number">0</span>]*math.sin(<span class="variable language_">self</span>.rotatey)*<span class="variable language_">self</span>.movespeed*<span class="number">0.01</span></span><br><span class="line"> <span class="variable language_">self</span>.posx+= <span class="variable language_">self</span>.movement[<span class="number">2</span>]*math.sin(<span class="variable language_">self</span>.rotatey+math.radians(<span class="number">90</span>))*<span class="variable language_">self</span>.movespeed*<span class="number">0.01</span></span><br><span class="line"> <span class="variable language_">self</span>.posy+= <span class="variable language_">self</span>.movement[<span class="number">1</span>]*<span class="variable language_">self</span>.movespeed*<span class="number">0.01</span></span><br><span class="line"> <span class="variable language_">self</span>.posz+= <span class="variable language_">self</span>.movement[<span class="number">0</span>]*math.cos(<span class="variable language_">self</span>.rotatey)*<span class="variable language_">self</span>.movespeed*<span class="number">0.01</span></span><br><span class="line"> <span class="variable language_">self</span>.posz+= <span class="variable language_">self</span>.movement[<span class="number">2</span>]*math.cos(<span class="variable language_">self</span>.rotatey+math.radians(<span class="number">90</span>))*<span class="variable language_">self</span>.movespeed*<span class="number">0.01</span></span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.controled:</span><br><span class="line"> centerx=<span class="variable language_">self</span>.geometry().center().x()</span><br><span class="line"> centery=<span class="variable language_">self</span>.geometry().center().y()</span><br><span class="line"> mousex=QCursor.pos().x()</span><br><span class="line"> mousey=QCursor.pos().y()</span><br><span class="line"> offsetx=centerx-mousex</span><br><span class="line"> offsety=centery-mousey</span><br><span class="line"> <span class="variable language_">self</span>.rotatex+=offsety*<span class="number">0.001</span> </span><br><span class="line"> <span class="variable language_">self</span>.rotatex=<span class="built_in">min</span>(math.radians(<span class="number">90</span>),<span class="variable language_">self</span>.rotatex)</span><br><span class="line"> <span class="variable language_">self</span>.rotatex=<span class="built_in">max</span>(math.radians(-<span class="number">90</span>),<span class="variable language_">self</span>.rotatex)<span class="comment">#绕x轴旋转的极限</span></span><br><span class="line"> <span class="variable language_">self</span>.rotatey+=offsetx*<span class="number">0.001</span></span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.rotatey>math.radians(<span class="number">180</span>):</span><br><span class="line"> <span class="variable language_">self</span>.rotatey-=math.radians(<span class="number">360</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.rotatey<math.radians(-<span class="number">180</span>):</span><br><span class="line"> <span class="variable language_">self</span>.rotatey+=math.radians(<span class="number">360</span>) <span class="comment">#绕y轴旋转处理</span></span><br><span class="line"> QCursor.setPos(<span class="variable language_">self</span>.geometry().center())</span><br></pre></td></tr></table></figure><h2 id="多面体"><a href="#多面体" class="headerlink" title="多面体"></a>多面体</h2><p>将线段相接,得到多面体。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Body</span>():</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,space,vertixes,edges</span>):</span><br><span class="line"> <span class="variable language_">self</span>.vertixes=vertixes</span><br><span class="line"> <span class="variable language_">self</span>.edges=[]</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> edges:</span><br><span class="line"> <span class="variable language_">self</span>.edges.append(Segment(Point(*(vertixes[i[<span class="number">0</span>]])),Point(*(vertixes[i[<span class="number">1</span>]]))))</span><br><span class="line"> <span class="variable language_">self</span>.space=space</span><br><span class="line"> <span class="variable language_">self</span>.space.objects.append(<span class="variable language_">self</span>)</span><br></pre></td></tr></table></figure><h3 id="矩体"><a href="#矩体" class="headerlink" title="矩体"></a>矩体</h3><p>矩体是一种特殊的多面体。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Cubold</span>(<span class="title class_ inherited__">Body</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,space,x,y,z,length,width,height</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__(space,[[x,y,z],[x+length,y,z],[x,y,z+width],[x+length,y,z+height],</span><br><span class="line"> [x,y+height,z],[x+length,y+height,z],[x,y+height,z+width],[x+length,y+height,z+length]],<span class="comment">#描述顶点坐标</span></span><br><span class="line"> [[<span class="number">0</span>,<span class="number">1</span>],[<span class="number">1</span>,<span class="number">3</span>],[<span class="number">2</span>,<span class="number">0</span>],[<span class="number">3</span>,<span class="number">2</span>],[<span class="number">4</span>,<span class="number">5</span>],[<span class="number">5</span>,<span class="number">7</span>],[<span class="number">6</span>,<span class="number">4</span>],[<span class="number">7</span>,<span class="number">6</span>],[<span class="number">0</span>,<span class="number">4</span>],[<span class="number">1</span>,<span class="number">5</span>],[<span class="number">2</span>,<span class="number">6</span>],[<span class="number">3</span>,<span class="number">7</span>]])<span class="comment">#连棱</span></span><br></pre></td></tr></table></figure><h2 id="平面文字"><a href="#平面文字" class="headerlink" title="平面文字"></a>平面文字</h2><p>没有什么特别的,但是设置了一个更新时会执行的函数</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Text2D</span>():</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,camera,x,y,content</span>) :</span><br><span class="line"> <span class="variable language_">self</span>.x=x</span><br><span class="line"> <span class="variable language_">self</span>.y=y</span><br><span class="line"> <span class="variable language_">self</span>.camera=camera</span><br><span class="line"> <span class="variable language_">self</span>.content=content</span><br><span class="line"> <span class="variable language_">self</span>.camera.objects2D.append(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">update</span>(<span class="params">camera</span>):</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"> <span class="variable language_">self</span>.updatefunc=update</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">setText</span>(<span class="params">self,content</span>):</span><br><span class="line"> <span class="variable language_">self</span>.content=content</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">setUpdate</span>(<span class="params">self,func</span>):</span><br><span class="line"> <span class="variable language_">self</span>.updatefunc=func</span><br></pre></td></tr></table></figure><h2 id="更新相机画面"><a href="#更新相机画面" class="headerlink" title="更新相机画面"></a>更新相机画面</h2><p>把当前相机所在空间中的每一个多面体的每一条棱画出来,同时也也要写文字,执行文字更新是的那个函数</p><p>使用<code>QPainter</code>。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Camera(QWidget):</span></span><br><span class="line"><span class="comment"># def paintEvent(self,event):</span></span><br><span class="line">painter = QPainter(<span class="variable language_">self</span>)</span><br><span class="line"> color=QColor()</span><br><span class="line"> color.setRgb(<span class="number">0</span>,<span class="number">0</span>,<span class="number">255</span>)</span><br><span class="line"> pen=QPen()</span><br><span class="line"> pen.setColor(color)</span><br><span class="line"> painter.setPen(pen)</span><br><span class="line"> <span class="keyword">if</span> <span class="variable language_">self</span>.controled:</span><br><span class="line"> painter.drawLine(<span class="variable language_">self</span>.width()/<span class="number">2</span>-<span class="number">2</span>,<span class="variable language_">self</span>.height()/<span class="number">2</span>,<span class="variable language_">self</span>.width()/<span class="number">2</span>+<span class="number">2</span>,<span class="variable language_">self</span>.height()/<span class="number">2</span>)</span><br><span class="line"> painter.drawLine(<span class="variable language_">self</span>.width()/<span class="number">2</span>,<span class="variable language_">self</span>.height()/<span class="number">2</span>-<span class="number">2</span>,<span class="variable language_">self</span>.width()/<span class="number">2</span>,<span class="variable language_">self</span>.height()/<span class="number">2</span>+<span class="number">2</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="variable language_">self</span>.space.objects:</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> i.edges:</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> x1,y1,x2,y2=j.paint(<span class="variable language_">self</span>)</span><br><span class="line"> painter.drawLine(x1,y1,x2,y2)</span><br><span class="line"> <span class="keyword">except</span>:</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="variable language_">self</span>.objects2D:</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">isinstance</span>(i,Text2D):</span><br><span class="line"> painter.drawText(i.x,i.y,i.content)</span><br><span class="line"> i.updatefunc(<span class="variable language_">self</span>)</span><br></pre></td></tr></table></figure><h1 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h1><p>我把这个文件叫做<code>threedengine.py</code>。同时建了一个测试文件<code>demo.py</code>。</p><h2 id="测试代码"><a href="#测试代码" class="headerlink" title="测试代码"></a>测试代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> threedengine</span><br><span class="line"><span class="keyword">import</span> math</span><br><span class="line">space=threedengine.Space()</span><br><span class="line">camera=threedengine.Camera(space,<span class="number">1000</span>,<span class="number">500</span>,<span class="string">'三维视图'</span>,<span class="number">800</span>,<span class="number">400</span>,<span class="number">300</span>)</span><br><span class="line">camera.launch()</span><br><span class="line">body=threedengine.Cubold(space,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>)</span><br><span class="line">text=threedengine.Text2D(camera,<span class="number">10</span>,<span class="number">10</span>,<span class="string">''</span>)</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">update</span>(<span class="params">camera</span>):</span><br><span class="line"> text.setText(<span class="string">'位置:(%f,%f,%f) 方向:%f° 俯仰:%f°'</span>%(camera.posx,camera.posy,camera.posz,math.degrees(camera.rotatey),math.degrees(camera.rotatex)))</span><br><span class="line">text.setUpdate(update)</span><br><span class="line">threedengine.run()</span><br></pre></td></tr></table></figure><h2 id="效果"><a href="#效果" class="headerlink" title="效果"></a>效果</h2><p><img src="https://s1.imagehub.cc/images/2024/11/24/33885258cb2ec9febc7db99b45a1715d.png" alt="image"></p><p>到这里这篇文章就结束了,886!</p>]]></content>
<summary type="html"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近比较忙,所以很久没更新。</p>
<p>之前玩过很多三维沙盒游戏,但是很好奇是如何实现那种三维投射的</p>
<p>于是最近写出来了一个三维引擎</p>
<h1 id="过程"><a href="#过程" class="headerlink" title=</summary>
<category term="三维引擎" scheme="https://blog.qyadbr.top/categories/%E4%B8%89%E7%BB%B4%E5%BC%95%E6%93%8E/"/>
<category term="三维引擎" scheme="https://blog.qyadbr.top/tags/%E4%B8%89%E7%BB%B4%E5%BC%95%E6%93%8E/"/>
<category term="数学" scheme="https://blog.qyadbr.top/tags/%E6%95%B0%E5%AD%A6/"/>
</entry>
<entry>
<title>自己动手写二维物理引擎(一)</title>
<link href="https://blog.qyadbr.top/posts/hexo7/"/>
<id>https://blog.qyadbr.top/posts/hexo7/</id>
<published>2024-10-20T13:33:20.000Z</published>
<updated>2025-05-28T13:02:55.462Z</updated>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>这一篇,继续之前的想法,开始写物理引擎的代码。</p><p>由于<strong>pygame不能同时打开多个窗口</strong>,我决定换<strong>Qt</strong>来显示窗口。</p><h1 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h1><h2 id="导入库"><a href="#导入库" class="headerlink" title="导入库"></a>导入库</h2><p>打开<code>physics.py</code></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PySide6 <span class="keyword">import</span> * </span><br><span class="line"><span class="keyword">import</span> math</span><br></pre></td></tr></table></figure><ul><li><code>PySide6</code>:这是Qt官方的PyQt6的库。这里我们用它来实现窗口以及内容的显示。</li><li><code>math</code>:Python数学库,用来处理一些高级的物理计算。</li></ul><h2 id="全局常量"><a href="#全局常量" class="headerlink" title="全局常量"></a>全局常量</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">DYMANIC=<span class="number">0</span></span><br><span class="line">STATIC=<span class="number">1</span></span><br></pre></td></tr></table></figure><p>这些常量定义了物体的状态等信息,后学会有更多常量写在这里。</p><h2 id="Qt应用程序"><a href="#Qt应用程序" class="headerlink" title="Qt应用程序"></a>Qt应用程序</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">qapp=QtWidgets.QApplication([])</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">run</span>():</span><br><span class="line"> qapp.<span class="built_in">exec</span>()</span><br></pre></td></tr></table></figure><p>之后在<code>demo.py</code>中运行<code>physics.run()</code>即可运行应用程序。</p><h1 id="物理空间"><a href="#物理空间" class="headerlink" title="物理空间"></a>物理空间</h1><p>编写一个<code>Space(QtWidegets.QWidget)</code>类来模拟一个物理空间,这将被显示为一个窗口。</p><h2 id="实例化"><a href="#实例化" class="headerlink" title="实例化"></a>实例化</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Space</span>(QtWidgets.QWidget):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,width,height,caption,g</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__()</span><br><span class="line"> <span class="variable language_">self</span>.width=width</span><br><span class="line"> <span class="variable language_">self</span>.height=height</span><br><span class="line"> <span class="variable language_">self</span>.caption=caption</span><br><span class="line"> <span class="variable language_">self</span>.objects=[]</span><br><span class="line"> <span class="variable language_">self</span>.g=g</span><br><span class="line"> <span class="variable language_">self</span>.timer = QtCore.QTimer()</span><br></pre></td></tr></table></figure><ul><li><code>width</code>:窗口的宽度</li><li><code>height</code>:窗口的高度</li><li><code>caption</code>:窗口的标题</li><li><code>objects</code>:物理空间中所有物体列表</li><li><code>g</code>:重力加速度(常量)</li><li><code>timer</code>:使用qt计时器,用来定时运行一些函数</li></ul><h2 id="启动窗口"><a href="#启动窗口" class="headerlink" title="启动窗口"></a>启动窗口</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Space(QtWidgets.QWidget):</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">launch</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.resize(<span class="variable language_">self</span>.width,<span class="variable language_">self</span>.height)</span><br><span class="line"> <span class="variable language_">self</span>.setWindowTitle(<span class="variable language_">self</span>.caption)</span><br><span class="line"> <span class="variable language_">self</span>.timer.start(<span class="number">5</span>)</span><br><span class="line"> <span class="variable language_">self</span>.timer.timeout.connect(<span class="variable language_">self</span>.moveObjects)</span><br><span class="line"> <span class="variable language_">self</span>.timer.timeout.connect(<span class="variable language_">self</span>.update)</span><br><span class="line"> <span class="variable language_">self</span>.show()</span><br></pre></td></tr></table></figure><p>该函数可以使物理空间窗口弹出并初始化。</p><h2 id="移动与绘制"><a href="#移动与绘制" class="headerlink" title="移动与绘制"></a>移动与绘制</h2><p>一个使窗口移动,并制造重力,另一个绘制。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Space(QtWidgets.QWidget):</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">moveObjects</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="variable language_">self</span>.objects:</span><br><span class="line"> <span class="keyword">if</span> i.stype==DYMANIC:</span><br><span class="line"> gravity=Force(<span class="variable language_">self</span>.g,math.pi/<span class="number">2</span>)</span><br><span class="line"> i.forceCompound(gravity)</span><br><span class="line"> i.move()</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">paintEvent</span>(<span class="params">self,event</span>):</span><br><span class="line"> painter = QtGui.QPainter(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="variable language_">self</span>.objects:</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">isinstance</span>(i,Circle):</span><br><span class="line"> painter.setPen(i.pen)</span><br><span class="line"> painter.drawEllipse(i.cpoint,i.r,i.r)</span><br><span class="line"> painter.drawLine(i.cpoint.x(),i.cpoint.y(),</span><br><span class="line"> i.cpoint.x()+i.r*math.cos(i.direction),i.cpoint.y()+i.r*math.sin(i.direction))</span><br><span class="line"> <span class="keyword">elif</span> <span class="built_in">isinstance</span>(i,Segment):</span><br><span class="line"> painter.setPen(i.pen)</span><br><span class="line"> painter.drawLine(i.x1,i.y1,i.x2,i.y2)</span><br></pre></td></tr></table></figure><h1 id="力与物体对象"><a href="#力与物体对象" class="headerlink" title="力与物体对象"></a>力与物体对象</h1><h2 id="力"><a href="#力" class="headerlink" title="力"></a>力</h2><p>力是最简单的一个类,它是一个<strong>向量</strong>,只有两个成员:方向和大小。</p><p>特别注意,所有的角单位都用弧度($\pi\space \text{rad}=180^{\circ}$)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Force</span>():</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,size,angle</span>):</span><br><span class="line"> <span class="variable language_">self</span>.size=size</span><br><span class="line"> <span class="variable language_">self</span>.angle=angle</span><br></pre></td></tr></table></figure><h2 id="物体对象"><a href="#物体对象" class="headerlink" title="物体对象"></a>物体对象</h2><p>物体对象有很多种,如刚体、流体、关节</p><h3 id="实例化-1"><a href="#实例化-1" class="headerlink" title="实例化"></a>实例化</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Object</span>():</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,z,window,color,mass,angle</span>):</span><br><span class="line"> <span class="variable language_">self</span>.z=z</span><br><span class="line"> <span class="variable language_">self</span>.window=window</span><br><span class="line"> <span class="variable language_">self</span>.window.objects.append(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.color=QtGui.QColor()</span><br><span class="line"> <span class="variable language_">self</span>.color.setRgb(color[<span class="number">0</span>],color[<span class="number">1</span>],color[<span class="number">2</span>])</span><br><span class="line"> <span class="variable language_">self</span>.mass=mass</span><br><span class="line"> <span class="variable language_">self</span>.velocity=<span class="number">0</span></span><br><span class="line"> <span class="variable language_">self</span>.angle=angle</span><br></pre></td></tr></table></figure><ul><li><code>z</code>:层坐标,<code>z</code>不同的两个元素不会发生碰撞。</li><li><code>window</code>:所在的窗口</li><li><code>color</code>:对象显示的颜色</li><li><code>mass</code>:对象的质量</li><li><code>velocity</code>:运动速度</li><li><code>angle</code>:运动方向</li></ul><h3 id="人为施力"><a href="#人为施力" class="headerlink" title="人为施力"></a>人为施力</h3><p><img src="https://image.qyadbr.top/file/97ff9678655c516d94095-c862322cf153358e6a.png" alt="image-20241020192920919"></p><p>可以看出,我们可以利用三角函数把物体当前的方向和速度分解为水平方向上的速度和垂直方向上的速度,对施加的力作同样的处理,将水平和垂直的分别相加再转换为新的速度和角度就可以实现人为施力。</p><p>于是又了下面的代码:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Object():</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">forceCompound</span>(<span class="params">self,add_force</span>):</span><br><span class="line"> cur_force_size=<span class="variable language_">self</span>.velocity</span><br><span class="line"> cur_force_dx=cur_force_size*math.cos(<span class="variable language_">self</span>.angle)+add_force.size*math.cos(add_force.angle)/<span class="variable language_">self</span>.mass</span><br><span class="line"> cur_force_dy=cur_force_size*math.sin(<span class="variable language_">self</span>.angle)+add_force.size*math.sin(add_force.angle)/<span class="variable language_">self</span>.mass</span><br><span class="line"> <span class="variable language_">self</span>.velocity=math.sqrt(cur_force_dx**<span class="number">2</span>+cur_force_dy**<span class="number">2</span>)</span><br><span class="line"> <span class="keyword">if</span> cur_force_dx>=<span class="number">0</span>:</span><br><span class="line"> <span class="variable language_">self</span>.angle=math.atan(cur_force_dy/cur_force_dx)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="variable language_">self</span>.angle=math.atan(cur_force_dy/cur_force_dx)+math.pi</span><br></pre></td></tr></table></figure><h3 id="删除对象"><a href="#删除对象" class="headerlink" title="删除对象"></a>删除对象</h3><p>把对象移除,不多赘述</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># class Object():</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">destroy</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.window.objects.remove(<span class="variable language_">self</span>)</span><br><span class="line"> <span class="variable language_">self</span>.window=<span class="literal">None</span></span><br><span class="line"> <span class="keyword">del</span> <span class="variable language_">self</span></span><br></pre></td></tr></table></figure><h1 id="刚体"><a href="#刚体" class="headerlink" title="刚体"></a>刚体</h1><p>目前先实现圆、线段。之后会实现多边形。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solid</span>(<span class="title class_ inherited__">Object</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,z,window,color,stype,mass,angle,direction</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__(z,window,color,mass,angle)</span><br><span class="line"> <span class="variable language_">self</span>.stype=stype</span><br><span class="line"> <span class="variable language_">self</span>.direction=direction</span><br><span class="line"> <span class="variable language_">self</span>.pen = QtGui.QPen(<span class="variable language_">self</span>.color)</span><br><span class="line"> <span class="variable language_">self</span>.pen.setWidth(<span class="number">2</span>)</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Circle</span>(<span class="title class_ inherited__">Solid</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,window,z,x,y,r,direction,stype,mass,angle=<span class="number">0</span>,color=(<span class="params"><span class="number">0</span>,<span class="number">0</span>,<span class="number">255</span></span>)</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__(z,window,color,stype,mass,angle,direction)</span><br><span class="line"> <span class="variable language_">self</span>.cpoint=QtCore.QPointF(x,y)</span><br><span class="line"> <span class="variable language_">self</span>.r=r</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">move</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.cpoint.setX(<span class="variable language_">self</span>.cpoint.x()+<span class="variable language_">self</span>.velocity*math.cos(<span class="variable language_">self</span>.angle))</span><br><span class="line"> <span class="variable language_">self</span>.cpoint.setY(<span class="variable language_">self</span>.cpoint.y()+<span class="variable language_">self</span>.velocity*math.sin(<span class="variable language_">self</span>.angle))</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">hit</span>(<span class="params">self,c</span>):</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Segment</span>(<span class="title class_ inherited__">Solid</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,window,z,x1,y1,x2,y2,direction,stype,mass,angle=<span class="number">0</span>,color=(<span class="params"><span class="number">0</span>,<span class="number">0</span>,<span class="number">255</span></span>)</span>):</span><br><span class="line"> <span class="built_in">super</span>().__init__(z,window,color,stype,mass,angle,direction)</span><br><span class="line"> <span class="variable language_">self</span>.x1=x1</span><br><span class="line"> <span class="variable language_">self</span>.y1=y1</span><br><span class="line"> <span class="variable language_">self</span>.x2=x2</span><br><span class="line"> <span class="variable language_">self</span>.y2=y2</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">move</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="variable language_">self</span>.x1+=<span class="variable language_">self</span>.velocity*math.cos(<span class="variable language_">self</span>.angle)</span><br><span class="line"> <span class="variable language_">self</span>.y1+=<span class="variable language_">self</span>.velocity*math.sin(<span class="variable language_">self</span>.angle)</span><br><span class="line"> <span class="variable language_">self</span>.x2+=<span class="variable language_">self</span>.velocity*math.cos(<span class="variable language_">self</span>.angle)</span><br><span class="line"> <span class="variable language_">self</span>.y2+=<span class="variable language_">self</span>.velocity*math.sin(<span class="variable language_">self</span>.angle)</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">hit</span>(<span class="params">self,c</span>):</span><br><span class="line"> <span class="keyword">pass</span></span><br></pre></td></tr></table></figure><h2 id="angle与direction的区别"><a href="#angle与direction的区别" class="headerlink" title="angle与direction的区别"></a><code>angle</code>与<code>direction</code>的区别</h2><p><code>angle</code>是指运动方向。而<code>direction</code>是只物体本身的朝向。</p><h1 id="效果测试"><a href="#效果测试" class="headerlink" title="效果测试"></a>效果测试</h1><p><code>demo.py</code></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> physics</span><br><span class="line"></span><br><span class="line">window1=physics.Space(<span class="number">1000</span>,<span class="number">600</span>,<span class="string">'123'</span>,<span class="number">9.8</span>)</span><br><span class="line">window1.launch()</span><br><span class="line">circle1=physics.Circle(window1,<span class="number">0</span>,<span class="number">100</span>,<span class="number">100</span>,<span class="number">40</span>,<span class="number">0</span>,physics.DYMANIC,<span class="number">1000</span>)</span><br><span class="line">force1=physics.Force(<span class="number">1000</span>,<span class="number">0</span>)</span><br><span class="line">circle1.forceCompound(force1)</span><br><span class="line">segment1=physics.Segment(window1,<span class="number">0</span>,<span class="number">50</span>,<span class="number">550</span>,<span class="number">950</span>,<span class="number">550</span>,<span class="number">0</span>,physics.STATIC,<span class="number">1000</span>)</span><br><span class="line">physics.run()</span><br></pre></td></tr></table></figure><p><img src="https://image.qyadbr.top/file/cb091da5c9e4ad39451f3-b40670a181745f9d8a.gif" alt="21-24-31"></p><h1 id="下期预告"><a href="#下期预告" class="headerlink" title="下期预告"></a>下期预告</h1><p>下一期会实现多边形以及碰撞检测。886!</p>]]></content>
<summary type="html"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>这一篇,继续之前的想法,开始写物理引擎的代码。</p>
<p>由于<strong>pygame不能同时打开多个窗口</strong>,我决定换<strong>Qt</strong>来显示窗口。</p>
<h1 id="开始"><a href="#开始" cla</summary>
<category term="物理引擎" scheme="https://blog.qyadbr.top/categories/%E7%89%A9%E7%90%86%E5%BC%95%E6%93%8E/"/>
<category term="物理引擎" scheme="https://blog.qyadbr.top/tags/%E7%89%A9%E7%90%86%E5%BC%95%E6%93%8E/"/>
</entry>
<entry>
<title>域名迁移到blog.qyadbr.top</title>
<link href="https://blog.qyadbr.top/posts/hexo6/"/>
<id>https://blog.qyadbr.top/posts/hexo6/</id>
<published>2024-10-04T09:37:08.000Z</published>
<updated>2025-05-28T13:02:58.771Z</updated>
<content type="html"><![CDATA[<p>之前有一个cloudflare免费二级域名<code>admibrill1.pages.dev</code>。</p><p>二级域名就是二级域名,有很多限制,加个友链都成问题。从八月开始就想买了,但是我自己买不了,没有条件。</p><p>等到9月21日(CSP-J/S第一轮)完成,30日出成绩,总算能买了,就去阿里云买了一个。</p><p>现在,有了全新的域名<code>blog.qyadbr.top</code>,<code>qyadbr.top</code>域名下面之后会做很多服务。</p><p>拜拜!</p>]]></content>
<summary type="html"><p>之前有一个cloudflare免费二级域名<code>admibrill1.pages.dev</code>。</p>
<p>二级域名就是二级域名,有很多限制,加个友链都成问题。从八月开始就想买了,但是我自己买不了,没有条件。</p>
<p>等到9月21日(CSP-J/S第一轮)完成,30日出成绩,总算能买了,就去阿里云买了一个。</p>
<p>现在,有了全新的域名<code>blog.qy</summary>
<category term="日常记录" scheme="https://blog.qyadbr.top/categories/%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95/"/>
<category term="日常记录" scheme="https://blog.qyadbr.top/tags/%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95/"/>
</entry>
<entry>
<title>自己动手写二维物理引擎(零)</title>
<link href="https://blog.qyadbr.top/posts/hexo5/"/>
<id>https://blog.qyadbr.top/posts/hexo5/</id>
<published>2024-09-28T04:06:08.000Z</published>
<updated>2025-05-28T13:03:02.153Z</updated>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><h2 id="为什么要写物理引擎"><a href="#为什么要写物理引擎" class="headerlink" title="为什么要写物理引擎"></a>为什么要写物理引擎</h2><p>其实在很久以前就用过别人的物理引擎了,可是这些引擎的功能不满足我的需求,比如说不支持流体的运动,以及实现把一个物体切割成两部分等,还可以制造燃烧,爆炸等效果,别人的物理引擎都没有。所以我决定自己先用python写一款物理引擎,后面再写成JavaScript来实现网页上的效果。</p><p>本文的编号是零,意思是这是写物理引擎前的准备工作。</p><h2 id="物理引擎的结构"><a href="#物理引擎的结构" class="headerlink" title="物理引擎的结构"></a>物理引擎的结构</h2><p>组成物理引擎的是窗口(Window),力(Force),物体(Object)和效果(Effect)。</p><p>窗口就是一个物理场,它记录了很多物理常量(如重力加速度等)</p><p>同时,它也是物体的载体,可以控制物体是否能跑到窗口外面去。</p><p>力可以使物体运动。会考虑重力、引力、浮力等。</p><p>物体分为三种:刚体(solid)、流体(liquid)、和关节(joint)</p><blockquote><p>刚体是指在运动中和受力作用后,形状和大小不变,而且内部各点的相对位置不变的物体。</p></blockquote><p>刚体可以分为线段(segment)球体(其实就是一个圆,circle)和多边形(polygon)。</p><p>每个刚体都会考虑碰撞。</p><p>流体分为牛顿流体和非牛顿流体。</p><p>关节可以约束两个刚体,可以伸缩。</p><p>效果则包含劈裂、燃烧等</p><h1 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h1><h2 id="新建文件"><a href="#新建文件" class="headerlink" title="新建文件"></a>新建文件</h2><p>在同一个目录下新建<code>physics.py</code>和<code>demo.py</code>。<code>physics.py</code>使我们的物理引擎。<code>demo.py</code>则用来测试</p><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p>physics.py</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pygame</span><br><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"><span class="keyword">from</span> pygame.<span class="built_in">locals</span> <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line">pygame.init()</span><br><span class="line"><span class="comment"># pygame.draw.circle(window, (0, 0, 255),[300,300], 170, 0)</span></span><br><span class="line"><span class="comment"># pygame.draw.polygon(window, (255,0,0), [[300,300],[100,400],[100,300]])</span></span><br><span class="line"><span class="comment"># pygame.draw.line(window, (0, 0, 0), [100, 300], [500, 300], 5)</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Window</span>():</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,width,height,caption</span>):</span><br><span class="line"> <span class="variable language_">self</span>.width=width</span><br><span class="line"> <span class="variable language_">self</span>.height=height</span><br><span class="line"> <span class="variable language_">self</span>.caption=caption</span><br><span class="line"> <span class="variable language_">self</span>.surface=pygame.display.set_mode((<span class="variable language_">self</span>.width,<span class="variable language_">self</span>.height))</span><br><span class="line"> <span class="variable language_">self</span>.bodies=[]</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">run</span>(<span class="params">self</span>):</span><br><span class="line"> pygame.display.set_caption(<span class="variable language_">self</span>.caption)</span><br><span class="line"> flag=<span class="literal">True</span></span><br><span class="line"> <span class="keyword">while</span> flag:</span><br><span class="line"> pygame.display.update()</span><br><span class="line"> <span class="keyword">for</span> event <span class="keyword">in</span> pygame.event.get():</span><br><span class="line"> <span class="keyword">if</span> event.<span class="built_in">type</span> == QUIT:</span><br><span class="line"> pygame.quit()</span><br><span class="line"> flag=<span class="literal">False</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Object</span>():</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solid</span>(<span class="title class_ inherited__">Object</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Liquid</span>(<span class="title class_ inherited__">Object</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Joint</span>(<span class="title class_ inherited__">Object</span>):</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> <span class="keyword">pass</span></span><br></pre></td></tr></table></figure><p>demo.py</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> physics</span><br><span class="line">window1=physics.Window(<span class="number">1000</span>,<span class="number">600</span>,<span class="string">'123'</span>)</span><br><span class="line">window1.run()</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><h2 id="为什么要写物理引擎"><a href="#为什么要写物理引擎" class="headerlink" title="为什么要写物理引擎"></a>为什么要写物理引擎</h2><p>其实在很久以前就用过别人的物理引擎了,可是这些引擎的功能不满足我的需求</summary>
<category term="物理引擎" scheme="https://blog.qyadbr.top/categories/%E7%89%A9%E7%90%86%E5%BC%95%E6%93%8E/"/>
<category term="物理引擎" scheme="https://blog.qyadbr.top/tags/%E7%89%A9%E7%90%86%E5%BC%95%E6%93%8E/"/>
</entry>
<entry>
<title>Markdown与外挂标签语法测试</title>
<link href="https://blog.qyadbr.top/posts/hexo4/"/>
<id>https://blog.qyadbr.top/posts/hexo4/</id>
<published>2024-09-15T13:05:08.000Z</published>
<updated>2025-05-28T13:03:05.517Z</updated>
<content type="html"><</span><br></pre></td></tr></table></figure><p>效果:</p><p>这是一个网址:<a href="https://blog.qyadbr.top">https://blog.qyadbr.top</a><br>这也是一个网址:<a href="https://blog.qyadbr.top">https://blog.qyadbr.top</a><br><a href="https://blog.qyadbr.top">Admibrill的博客</a></p><h3 id="插入图片链接"><a href="#插入图片链接" class="headerlink" title="插入图片链接"></a>插入图片链接</h3><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><p>效果:</p><p><img src="https://source-admibrill.pages.dev/file/f69c9c86b22cb90df18a1.png" alt="Admibrill的头像"></p><h2 id="分割线"><a href="#分割线" class="headerlink" title="分割线"></a>分割线</h2><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="strong">__<span class="emphasis">_</span></span></span><br></pre></td></tr></table></figure><p>效果:</p><hr><h2 id="代码块"><a href="#代码块" class="headerlink" title="代码块"></a>代码块</h2><h3 id="行内代码块"><a href="#行内代码块" class="headerlink" title="行内代码块"></a>行内代码块</h3><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="code">`abc`</span></span><br></pre></td></tr></table></figure><p>效果:<br><code>abc</code></p><h3 id="整段代码块"><a href="#整段代码块" class="headerlink" title="整段代码块"></a>整段代码块</h3><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="code">```markdown</span></span><br><span class="line"><span class="code">你好</span></span><br><span class="line"><span class="code">(为了显示这三个`添加了这个括号和这个括号内的内容)```</span></span><br></pre></td></tr></table></figure><p>效果<br><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">你好</span><br></pre></td></tr></table></figure><br>2.6 引用<br><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="quote">> 有志者,</span></span><br><span class="line"><span class="quote">> 事竟成.</span></span><br></pre></td></tr></table></figure><br>效果:</p><blockquote><p>有志者,<br>事竟成.</p></blockquote><h2 id="列表"><a href="#列表" class="headerlink" title="列表"></a>列表</h2><h3 id="无序列表"><a href="#无序列表" class="headerlink" title="无序列表"></a>无序列表</h3><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">-</span> 第一项</span><br><span class="line"><span class="bullet">-</span> 第二项</span><br><span class="line"><span class="bullet">-</span> 第三项</span><br></pre></td></tr></table></figure><p>效果:</p><ul><li>第一项</li><li>第二项</li><li>第三项<h3 id="有序列表"><a href="#有序列表" class="headerlink" title="有序列表"></a>有序列表</h3><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">1.</span> 第一项</span><br><span class="line"><span class="bullet">2.</span> 第二项</span><br><span class="line"><span class="bullet">3.</span> 第三项</span><br></pre></td></tr></table></figure>效果:</li></ul><ol><li>第一项</li><li>第二项</li><li>第三项</li></ol><h2 id="表格"><a href="#表格" class="headerlink" title="表格"></a>表格</h2><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">表头1|表头2|表头3</span><br><span class="line">---|---|---</span><br><span class="line">内容|内容|内容</span><br><span class="line">内容|内容|内容</span><br><span class="line">内容|内容|内容</span><br><span class="line">内容|内容|内容</span><br></pre></td></tr></table></figure><div class="table-container"><table><thead><tr><th>表头1</th><th>表头2</th><th>表头3</th></tr></thead><tbody><tr><td>内容</td><td>内容</td><td>内容</td></tr><tr><td>内容</td><td>内容</td><td>内容</td></tr><tr><td>内容</td><td>内容</td><td>内容</td></tr><tr><td>内容</td><td>内容</td><td>内容</td></tr></tbody></table></div><h1 id="外挂标签"><a href="#外挂标签" class="headerlink" title="外挂标签"></a>外挂标签</h1><p><a href="https://www.fomal.cc/posts/2013454d.html">https://www.fomal.cc/posts/2013454d.html</a></p>]]></content>
<summary type="html"><h1 id="基本语法"><a href="#基本语法" class="headerlink" title="基本语法"></a>基本语法</h1><h2 id="分级标题"><a href="#分级标题" class="headerlink" title="分级标题"></a>分级标题</h2><figure class="highlight markdown"><table><tr><td </summary>
<category term="代码语法" scheme="https://blog.qyadbr.top/categories/%E4%BB%A3%E7%A0%81%E8%AF%AD%E6%B3%95/"/>
<category term="Markdown" scheme="https://blog.qyadbr.top/tags/Markdown/"/>
<category term="测试" scheme="https://blog.qyadbr.top/tags/%E6%B5%8B%E8%AF%95/"/>
<category term="外挂标签" scheme="https://blog.qyadbr.top/tags/%E5%A4%96%E6%8C%82%E6%A0%87%E7%AD%BE/"/>
</entry>
<entry>
<title>Hexo博客0氪建站记录(下)</title>
<link href="https://blog.qyadbr.top/posts/hexo3/"/>
<id>https://blog.qyadbr.top/posts/hexo3/</id>
<published>2024-08-29T07:57:55.000Z</published>
<updated>2025-05-28T13:03:08.360Z</updated>
<content type="html"><![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><ol><li><p>我还没说过我域名是怎么来的</p></li><li><p><del>建站不知道多少天了</del>,我的朋友圈竟然还长这样:<br><img src="https://source-admibrill.pages.dev/file/7bd9ae102aa38c6193185.png" alt=""><br>在看了清羽飞扬的<a href="https://blog.liushen.fun/posts/4dc716ec/">Friend-Circle-Lite:轻量友链朋友圈</a>之后,手痒了,决定搞一个。</p></li><li><p>还有,我还需要自建图床。于是使用<a href="https://github.com/cf-pages/Telegraph-Image">Telegraph Image</a>做了一个。之前用github搞过一个,可是听别人说,github禁止把仓库当图床,轻则删库,重则封号,仓库大于1GB就要人工审核,所以就用了这种方法。</p></li></ol><h2 id="使用cloudflare-Pages部署Github-Pages的网站(?)"><a href="#使用cloudflare-Pages部署Github-Pages的网站(?)" class="headerlink" title="使用cloudflare Pages部署Github Pages的网站(?)"></a>使用cloudflare Pages部署Github Pages的网站(?)</h2><p>实在无法理解,之前那个<code>admibrill.github.io</code>蛮好,但过了几天就无法访问了(?),但是我的一些朋友还能访问(?),为了让自己能够访问,我把github上的项目仓库在cf上又部署了一次。</p><p>首先,打开cloudflare,找到<code>Workers和Pages</code>然后进入,点击创建,创建一个部署。</p><p><img src="https://source-admibrill.pages.dev/file/06561d555b0e66e7ef27c.png" alt=""></p><p><img src="https://source-admibrill.pages.dev/file/9e300d58129a590f871dc.png" alt=""></p><p>选择仓库,等程序跑完就可以了。</p><h2 id="友链朋友圈"><a href="#友链朋友圈" class="headerlink" title="友链朋友圈"></a>友链朋友圈</h2><p>这一部分参考清羽飞扬的博文,<del>清羽的里面有很多碎碎念</del>,我精简一点。</p><h3 id="json存储文件"><a href="#json存储文件" class="headerlink" title=".json存储文件"></a>.json存储文件</h3><p>这个文件用于记录朋友圈里会显示的友站。</p><p>我们的友链有很多,我们不能每次改了友链都要改这个json文件。于是清羽飞扬提供了生成.json文件的JavaScript:</p><p>在<code>[blogroot]</code>新建文件<code>link.js</code>,写入如下内容:(感谢代码)</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">YML</span> = <span class="built_in">require</span>(<span class="string">'yamljs'</span>)</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> blacklist = [<span class="string">"友站名称1"</span>, <span class="string">"友站名称2"</span>, <span class="string">"友站名称3"</span>]; <span class="comment">// 由于某种原因,不想订阅的列表</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> friends = [],</span><br><span class="line"> data_f = <span class="variable constant_">YML</span>.<span class="title function_">parse</span>(fs.<span class="title function_">readFileSync</span>(<span class="string">'source/_data/link.yml'</span>).<span class="title function_">toString</span>().<span class="title function_">replace</span>(<span class="regexp">/(?<=rss:)\s*\n/g</span>, <span class="string">' ""\n'</span>));</span><br><span class="line"></span><br><span class="line">data_f.<span class="title function_">forEach</span>(<span class="function">(<span class="params">entry, index</span>) =></span> {</span><br><span class="line"> <span class="keyword">let</span> lastIndex = <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (index < lastIndex) {</span><br><span class="line"> <span class="keyword">const</span> filteredLinkList = entry.<span class="property">link_list</span>.<span class="title function_">filter</span>(<span class="function"><span class="params">linkItem</span> =></span> !blacklist.<span class="title function_">includes</span>(linkItem.<span class="property">name</span>));</span><br><span class="line"> friends = friends.<span class="title function_">concat</span>(filteredLinkList);</span><br><span class="line"> }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="comment">// 根据规定的格式构建 JSON 数据</span></span><br><span class="line"><span class="keyword">const</span> friendData = {</span><br><span class="line"> <span class="attr">friends</span>: friends.<span class="title function_">map</span>(<span class="function"><span class="params">item</span> =></span> {</span><br><span class="line"> <span class="keyword">return</span> [item.<span class="property">name</span>, item.<span class="property">link</span>, item.<span class="property">avatar</span>];</span><br><span class="line"> })</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将 JSON 对象转换为字符串</span></span><br><span class="line"><span class="keyword">const</span> friendJSON = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(friendData, <span class="literal">null</span>, <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 写入 friend.json 文件</span></span><br><span class="line">fs.<span class="title function_">writeFileSync</span>(<span class="string">'./source/friend.json'</span>, friendJSON);</span><br><span class="line"><span class="comment">//在控制台提示</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'friend.json 文件已生成。'</span>);</span><br></pre></td></tr></table></figure><p>然后我们每次更新博客,就得多加一条,保证没有友链漏掉:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node link.js;..... <span class="comment">#...为其他指令</span></span><br></pre></td></tr></table></figure><p><strong>现在就更新一次,确保friend.json上传到了网站里!</strong></p><h3 id="后端部署"><a href="#后端部署" class="headerlink" title="后端部署"></a>后端部署</h3><p>首先,前往清羽的仓库<a href="https://github.com/willow-god/Friend-Circle-Lite">willow-god/Friend-Circle-Lite: 🐱一个精简版,无后端,且仅利用github action运行的精简版友链朋友圈程序,兼容fc的json格式信息,同时支持推送友圈更新,支持他人订阅个人站点并在更新时发送邮箱推送</a>把仓库Fork复制到自己的账号下:</p><p><img src="https://source-admibrill.pages.dev/file/0457a14794145a11dcbb8.png" alt=""></p><p>然后到自己的账号里的这个仓库,找到<code>conf.yml</code></p><p><img src="https://source-admibrill.pages.dev/file/16d2402b0ef56f0b5ce19.png" alt=""></p><p>修改配置:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 爬虫相关配置</span></span><br><span class="line"><span class="comment"># 解释:使用request实现友链文章爬取,并放置到根目录的all.json下</span></span><br><span class="line"><span class="comment"># enable: 是否启用爬虫</span></span><br><span class="line"><span class="comment"># json_url: 请填写对应格式json的地址,仅支持网络地址</span></span><br><span class="line"><span class="comment"># article_count: 请填写每个博客需要获取的最大文章数量</span></span><br><span class="line"><span class="comment"># marge_result: 是否合并多个json文件,若为true则会合并指定网络地址和本地地址的json文件</span></span><br><span class="line"><span class="comment"># enable: 是否启用合并功能,该功能提供与自部署的友链合并功能,可以解决服务器部分国外网站无法访问的问题</span></span><br><span class="line"><span class="comment"># marge_json_path: 请填写网络地址的json文件,用于合并,不带空格!!!</span></span><br><span class="line"><span class="attr">spider_settings:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">json_url:</span> <span class="string">"https://blog.qyadbr.top/friend.json"</span> <span class="comment">########一定要改,不然是我的,改成"自己的网站/friend.json"</span></span><br><span class="line"> <span class="attr">article_count:</span> <span class="number">15</span></span><br><span class="line"> <span class="attr">merge_result:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">merge_json_url:</span> <span class="string">"https://fc.liushen.fun"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 邮箱推送功能配置,暂未实现,等待后续开发</span></span><br><span class="line"><span class="comment"># 解释:每天为指定邮箱推送所有友链文章的更新,仅能指定一个</span></span><br><span class="line"><span class="comment"># enable: 是否启用邮箱推送功能</span></span><br><span class="line"><span class="comment"># to_email: 收件人邮箱地址</span></span><br><span class="line"><span class="comment"># subject: 邮件主题</span></span><br><span class="line"><span class="comment"># body_template: 邮件正文的 HTML 模板文件</span></span><br><span class="line"><span class="attr">email_push:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span> <span class="comment">########### 我不需要,就没有启用</span></span><br><span class="line"> <span class="attr">to_email:</span> <span class="string">recipient@example.com</span></span><br><span class="line"> <span class="attr">subject:</span> <span class="string">"今天的 RSS 订阅更新"</span></span><br><span class="line"> <span class="attr">body_template:</span> <span class="string">"rss_template.html"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 邮箱issue订阅功能配置</span></span><br><span class="line"><span class="comment"># 解释:向在issue中提取的所有邮箱推送您网站中的更新,添加邮箱和删除邮箱均通过添加issue对应格式实现</span></span><br><span class="line"><span class="comment"># enable: 是否启用邮箱推送功能</span></span><br><span class="line"><span class="comment"># github_username: GitHub 用户名,用于构建issue api地址</span></span><br><span class="line"><span class="comment"># github_repo: GitHub 仓库名,用于构建issue api地址</span></span><br><span class="line"><span class="comment"># your_blog_url: 你的博客地址</span></span><br><span class="line"><span class="attr">rss_subscribe:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">false</span> <span class="comment">############ 我不需要,就没有启用</span></span><br><span class="line"> <span class="attr">github_username:</span> <span class="string">willow-god</span></span><br><span class="line"> <span class="attr">github_repo:</span> <span class="string">Friend-Circle-Lite</span></span><br><span class="line"> <span class="attr">your_blog_url:</span> <span class="string">https://blog.qyadbr.top/</span></span><br><span class="line"> <span class="attr">email_template:</span> <span class="string">"./rss_subscribe/email_template.html"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># SMTP 配置</span></span><br><span class="line"><span class="comment"># 解释:使用其中的相关配置实现上面两种功能,若无推送要求可以不配置,请将以上两个配置置为false</span></span><br><span class="line"><span class="comment"># email: 发件人邮箱地址</span></span><br><span class="line"><span class="comment"># server: SMTP 服务器地址</span></span><br><span class="line"><span class="comment"># port: SMTP 端口号</span></span><br><span class="line"><span class="comment"># use_tls: 是否使用 tls 加密</span></span><br><span class="line"><span class="attr">smtp:</span></span><br><span class="line"> <span class="attr">email:</span> <span class="number">3162475700</span><span class="string">@qq.com</span></span><br><span class="line"> <span class="attr">server:</span> <span class="string">smtp.qq.com</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">587</span></span><br><span class="line"> <span class="attr">use_tls:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><p><img src="https://source-admibrill.pages.dev/file/8901ef3ed5250a9a41ada.png" alt=""></p><h3 id="第一次运行测试"><a href="#第一次运行测试" class="headerlink" title="第一次运行测试"></a>第一次运行测试</h3><p>按图示操作,运行workflow:</p><p><img src="https://source-admibrill.pages.dev/file/8babe6f6beed7e37405da.png" alt=""></p><p>然后我们点开一条记录,查看<code>Check RSS feeds</code></p><p><img src="https://source-admibrill.pages.dev/file/3b9b57ffb17f3a68af552.png" alt=""></p><p>有这样的输出即为正常。</p><h3 id="使用cloudflare托管后端"><a href="#使用cloudflare托管后端" class="headerlink" title="使用cloudflare托管后端"></a>使用cloudflare托管后端</h3><p>按照前面cloudflare部署的方法,部署一个后端地址。这个地址将会被我们当做后端。</p><h3 id="前端部署"><a href="#前端部署" class="headerlink" title="前端部署"></a>前端部署</h3><p>在<code>Blogroot/source/fcircle/index.md</code>中添加如下内容(其实就是加html):</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"friend-circle-lite-root"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="title class_">UserConfig</span> === <span class="string">'undefined'</span>) {</span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">var</span> <span class="title class_">UserConfig</span> = {</span></span><br><span class="line"><span class="language-javascript"> <span class="comment">// 填写你的fc Lite地址</span></span></span><br><span class="line"><span class="language-javascript"> <span class="attr">private_api_url</span>: <span class="string">'https://fc.liushen.fun/'</span>,</span></span><br><span class="line"><span class="language-javascript"> <span class="comment">// 点击加载更多时,一次最多加载几篇文章,默认20</span></span></span><br><span class="line"><span class="language-javascript"> <span class="attr">page_turning_number</span>: <span class="number">20</span>,</span></span><br><span class="line"><span class="language-javascript"> <span class="comment">// 头像加载失败时,默认头像地址</span></span></span><br><span class="line"><span class="language-javascript"> <span class="attr">error_img</span>: <span class="string">'https://pic.imgdb.cn/item/6695daa4d9c307b7e953ee3d.jpg'</span>,</span></span><br><span class="line"><span class="language-javascript"> }</span></span><br><span class="line"><span class="language-javascript"> }</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"https://fastly.jsdelivr.net/gh/willow-god/Friend-Circle-Lite/main/fclite.min.css"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://fastly.jsdelivr.net/gh/willow-god/Friend-Circle-Lite/main/fclite.min.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>ok,朋友圈功能到此完成。</p><h2 id="Telegraph-Image图床"><a href="#Telegraph-Image图床" class="headerlink" title="Telegraph Image图床"></a>Telegraph Image图床</h2><p>在写博客的时候,常常需要图片<del>(比如说刚才那个部分就弄了n次图片)</del>。</p><p>为了方便自己,自己建了个图床。</p><h3 id="部署图床"><a href="#部署图床" class="headerlink" title="部署图床"></a>部署图床</h3><p>首先还是fork仓库(不需要图了吧),<a href="https://github.com/cf-pages/Telegraph-Image">cf-pages/Telegraph-Image: Image Hosting solution, Flickr/imgur alternative, make it easy for users to share their images. Using Cloudflare Pages and Telegraph. (github.com)</a>。</p><p>然后把把仓库部署的cloudflare上(不需要图了吧)。</p><h3 id="使用PicGo方便Typora上传图片"><a href="#使用PicGo方便Typora上传图片" class="headerlink" title="使用PicGo方便Typora上传图片"></a>使用PicGo方便Typora上传图片</h3><p>然后下载安装PicGo,进入插件,安装插件telegraph-image-uploader</p><p>进入图床设置</p><p><img src="https://source-admibrill.pages.dev/file/74f1f956e5cb8d939db46.png" alt="image-20240829221408459"></p><p>设置URL为你的图床地址,就可以使用PicGo上传啦!</p><p>接着使用Markdown编辑器Typora:</p><p><img src="https://source-admibrill.pages.dev/file/6ac87f110fed6c040f5e5.png" alt=""></p><p>现在截图复制粘贴到Typora里就可以上传了。</p><h3 id="使用Python来删除Typora创建的临时图片文件"><a href="#使用Python来删除Typora创建的临时图片文件" class="headerlink" title="使用Python来删除Typora创建的临时图片文件"></a>使用Python来删除Typora创建的临时图片文件</h3><p>但是有个问题:我们粘进Typora的文件,会先放到<code>C:\Users\<username>\AppData\Roaming\Typora\typora-user-images</code>这个文件夹里,久而久之,文件会越来越多,Typora却不自己删除。于是我决定用Python来删除这些文件。</p><h4 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h4><p>在任意位置新建一个<code>delete.py</code>,写入如下代码:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 导入库,放心,都是Python标准库,不用pip</span></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="comment"># 编辑配置</span></span><br><span class="line">username=<span class="string">'乐乐'</span> <span class="comment">#这是我电脑用户名,需要改成自己的</span></span><br><span class="line">path=<span class="string">'C:\\Users\\'</span>+username+<span class="string">'\\AppData\\Roaming\\Typora\\typora-user-images\\'</span> <span class="comment">#检查的目录</span></span><br><span class="line">checktime=<span class="number">5</span> <span class="comment">#每次检查新文件和删除文件的间隔时间</span></span><br><span class="line">deltime=<span class="number">50</span> <span class="comment">#每个文件存在大于多少秒就要删除,足以等待图片上传完</span></span><br><span class="line"><span class="comment"># 启动</span></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>: </span><br><span class="line"> listd=os.listdir(path)</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> listd:</span><br><span class="line"> <span class="keyword">if</span> time.time()-os.path.getctime(path+i)>deltime:</span><br><span class="line"> os.remove(path+i)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'removed '</span>+path+i)</span><br><span class="line"> time.sleep(checktime)</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>到此hexo建站教程就完结了,886!</p>]]></content>
<summary type="html"><h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><ol>
<li><p>我还没说过我域名是怎么来的</p>
</li>
<li><p><del>建站不知道多少天了</del>,我的朋友圈竟然还长这样:<br><img src="https://source-admibrill.pages.dev/file/7bd</summary>
<category term="Hexo" scheme="https://blog.qyadbr.top/categories/Hexo/"/>
<category term="Hexo" scheme="https://blog.qyadbr.top/tags/Hexo/"/>
<category term="建站" scheme="https://blog.qyadbr.top/tags/%E5%BB%BA%E7%AB%99/"/>
<category term="免费" scheme="https://blog.qyadbr.top/tags/%E5%85%8D%E8%B4%B9/"/>
</entry>
<entry>
<title>Hexo博客0氪建站记录(中)</title>
<link href="https://blog.qyadbr.top/posts/hexo2/"/>
<id>https://blog.qyadbr.top/posts/hexo2/</id>
<published>2024-08-25T07:57:55.000Z</published>
<updated>2025-05-28T13:03:11.370Z</updated>
<content type="html"><![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>上次,我们完成了Hexo框架的搭建。这次,我讲如何美化博客。</p><p>一打开博客页面,是一个单调的LandScape主题,没有首页,还有一篇hello world的英文文章。</p><p>想自己装饰那么多肯定不容易,于是我们就要去<a href="https://hexo.io/zh-cn">hexo官网</a>来选择一个好看的主题来装饰。</p><p>主题就是一个模版,有很多选项,这就是主题的配置,可以自己来设置。</p><p>看了一些教程,也改了很多,有一小部分是自己改的。</p><p>我使用的<a href="https://github.com/anzhiyu-c/hexo-theme-anzhiyu">安知鱼</a>主题,是一款可用度较高的主题,支持许多功能,推荐使用。</p><h2 id="启动!"><a href="#启动!" class="headerlink" title="启动!"></a>启动!</h2><p>众所周知,静态网页是由三门语言编写的:</p><ul><li>HTML:超文本标记语言,有许多标签,有不同的功能,可以生成一个网页框架。</li><li>CSS:层叠样式表,用于给框架加上华丽的样式。</li><li>JS:java网页脚本。用于交互。</li></ul><p>而博客魔改的重点就在CSS和JS上。</p><p>博客有很多魔改都是看的<a href="www.fomal.cc">Fomal大佬</a>整理的教程,就把采纳了的和自己改的写在这里。</p><p>安知鱼主题的末尾处有一个<code>inject:</code>配置项,这里可以用于在网页头和尾引入外链css和js文件。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">inject:</span> </span><br><span class="line"> <span class="attr">head:</span></span><br><span class="line"> <span class="string">...</span></span><br><span class="line"> <span class="attr">bottom:</span></span><br><span class="line"> <span class="string">...</span></span><br></pre></td></tr></table></figure><p>CSS文件一般放在head内,因为样式需要再预加载完成前渲染,这样就可以给让网页访问者更好的体验。</p><p>而JS一般放在bottom,因为JS时常需要获取HTML中的元素,如果在head就引入,执行,那么就有可能造成元素获取不到,返回了null,然这个js脚本执行中止。</p><h2 id="魔改开始!!!"><a href="#魔改开始!!!" class="headerlink" title="魔改开始!!!"></a>魔改开始!!!</h2><p><del>从这里开始,有部分内容都是链接</del></p><h3 id="黑夜霓虹灯、星空和流行特效重构"><a href="#黑夜霓虹灯、星空和流行特效重构" class="headerlink" title="黑夜霓虹灯、星空和流行特效重构"></a>黑夜霓虹灯、星空和流行特效重构</h3><p><a href="https://www.fomal.cc/posts/eec9786.html">Hexo博客魔改教程总结(一) | Fomalhaut🥝</a></p><h3 id="外挂标签的引入"><a href="#外挂标签的引入" class="headerlink" title="外挂标签的引入"></a>外挂标签的引入</h3><p><a href="https://akilar.top/posts/615e2dec/">Tag Plugins Plus | Akilarの糖果屋</a></p><h3 id="鼠标样式"><a href="#鼠标样式" class="headerlink" title="鼠标样式"></a>鼠标样式</h3><p><a href="https://www.fomal.cc/posts/5389e93f.html">Hexo博客魔改教程总结(二)| Fomalhaut🥝</a></p><h3 id="右下角工具按钮显示阅读进度"><a href="#右下角工具按钮显示阅读进度" class="headerlink" title="右下角工具按钮显示阅读进度"></a>右下角工具按钮显示阅读进度</h3><p><a href="https://blog.leonus.cn/2022/percent.html">返回顶部显示网页阅读进度 | Leonus</a></p><h3 id="Vue-Element样式弹窗"><a href="#Vue-Element样式弹窗" class="headerlink" title="Vue+Element样式弹窗"></a>Vue+Element样式弹窗</h3><p><a href="https://www.fomal.cc/posts/2d7ac914.html">Hexo博客魔改教程总结(三) | Fomalhaut🥝</a></p><h3 id="文章统计图"><a href="#文章统计图" class="headerlink" title="文章统计图"></a>文章统计图</h3><p><a href="https://blog.eurkon.com/post/1213ef82.html">Hexo 博客文章统计图 | Eurkon</a></p><h3 id="公告栏欢迎信息"><a href="#公告栏欢迎信息" class="headerlink" title="公告栏欢迎信息"></a>公告栏欢迎信息</h3><p><a href="https://ichika.cc/Article/beautiful_IPLocation/">给博客添加腾讯地图定位并制作个性欢迎 | ichikaの小窝</a></p><p>你以为公告栏欢迎信息这就结束了?NO!NO!NO!</p><p>由于<a href="https://lbs.qq.com/">腾讯定位服务</a>实在太抠门,每天就让一次请求,于是我找来了<a href="ip-api.com">ip-api.com</a>(主打一个0氪)</p><p>之前的<del><code>txmap.js</code></del>改成这样:感谢ichika提供的代码(因为换了API,响应结果的结构都变了,于是有很多地方要改,于是全粘进来)</p><p>(是不是应该换个文件名?)</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//get请求</span></span><br><span class="line">$.<span class="title function_">ajax</span>({</span><br><span class="line"> <span class="attr">type</span>: <span class="string">'get'</span>,</span><br><span class="line"> <span class="attr">url</span>: <span class="string">'http://ip-api.com/json/?fields=status,message,continent,continentCode,country,countryCode,region,regionName,city,district,zip,lat,lon,timezone,offset,currency,isp,org,as,asname,reverse,mobile,proxy,hosting,query&lang=zh-CN'</span>,</span><br><span class="line"> <span class="attr">data</span>: {</span><br><span class="line"> <span class="attr">callback</span>: <span class="string">'jsonp'</span>,</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">dataType</span>: <span class="string">'jsonp'</span>,</span><br><span class="line"> <span class="attr">success</span>: <span class="keyword">function</span> (<span class="params">res</span>) {</span><br><span class="line"> ipLoacation = res;</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getDistance</span>(<span class="params">e1, n1, e2, n2</span>) {</span><br><span class="line"> <span class="keyword">const</span> R = <span class="number">6371</span></span><br><span class="line"> <span class="keyword">const</span> { sin, cos, asin, <span class="variable constant_">PI</span>, hypot } = <span class="title class_">Math</span></span><br><span class="line"> <span class="keyword">let</span> <span class="title function_">getPoint</span> = (<span class="params">e, n</span>) => {</span><br><span class="line"> e *= <span class="variable constant_">PI</span> / <span class="number">180</span></span><br><span class="line"> n *= <span class="variable constant_">PI</span> / <span class="number">180</span></span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">x</span>: <span class="title function_">cos</span>(n) * <span class="title function_">cos</span>(e), <span class="attr">y</span>: <span class="title function_">cos</span>(n) * <span class="title function_">sin</span>(e), <span class="attr">z</span>: <span class="title function_">sin</span>(n) }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> a = <span class="title function_">getPoint</span>(e1, n1)</span><br><span class="line"> <span class="keyword">let</span> b = <span class="title function_">getPoint</span>(e2, n2)</span><br><span class="line"> <span class="keyword">let</span> c = <span class="title function_">hypot</span>(a.<span class="property">x</span> - b.<span class="property">x</span>, a.<span class="property">y</span> - b.<span class="property">y</span>, a.<span class="property">z</span> - b.<span class="property">z</span>)</span><br><span class="line"> <span class="keyword">let</span> r = <span class="title function_">asin</span>(c / <span class="number">2</span>) * <span class="number">2</span> * R</span><br><span class="line"> <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">round</span>(r*<span class="number">1000</span>)/<span class="number">1000</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">showWelcome</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">let</span> dist = <span class="title function_">getDistance</span>(<span class="number">114.337006</span>, <span class="number">30.525186</span>, ipLoacation.<span class="property">lon</span>, ipLoacation.<span class="property">lat</span>); <span class="comment">//这里换成自己的经纬度</span></span><br><span class="line"> <span class="keyword">let</span> pos = ipLoacation.<span class="property">country</span>;</span><br><span class="line"> <span class="keyword">let</span> ip;</span><br><span class="line"> <span class="keyword">let</span> posdesc;</span><br><span class="line"> <span class="comment">//根据国家、省份、城市信息自定义欢迎语</span></span><br><span class="line"> <span class="keyword">switch</span> (ipLoacation.<span class="property">country</span>) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"日本"</span>:</span><br><span class="line"> posdesc = <span class="string">"よろしく,一起去看樱花吗"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"美国"</span>:</span><br><span class="line"> posdesc = <span class="string">"Let us live in peace!"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"英国"</span>:</span><br><span class="line"> posdesc = <span class="string">"想同你一起夜乘伦敦眼"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"俄罗斯"</span>:</span><br><span class="line"> posdesc = <span class="string">"干了这瓶伏特加!"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"法国"</span>:</span><br><span class="line"> posdesc = <span class="string">"C'est La Vie"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"德国"</span>:</span><br><span class="line"> posdesc = <span class="string">"Die Zeit verging im Fluge."</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"澳大利亚"</span>:</span><br><span class="line"> posdesc = <span class="string">"一起去大堡礁吧!"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"加拿大"</span>:</span><br><span class="line"> posdesc = <span class="string">"拾起一片枫叶赠予你"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"中国"</span>:</span><br><span class="line"> pos = ipLoacation.<span class="property">country</span>+ <span class="string">" "</span> +ipLoacation.<span class="property">regionName</span> + <span class="string">" "</span> + ipLoacation.<span class="property">city</span>;</span><br><span class="line"> ip = ipLoacation.<span class="property">query</span>;</span><br><span class="line"> <span class="keyword">switch</span> (ipLoacation.<span class="property">regionName</span>) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"北京"</span>:</span><br><span class="line"> posdesc = <span class="string">"北——京——欢迎你~~~"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"天津"</span>:</span><br><span class="line"> posdesc = <span class="string">"讲段相声吧。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"河北省"</span>:</span><br><span class="line"> posdesc = <span class="string">"山势巍巍成壁垒,天下雄关。铁马金戈由此向,无限江山。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"山西省"</span>:</span><br><span class="line"> posdesc = <span class="string">"展开坐具长三尺,已占山河五百余。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"内蒙古自治区"</span>:</span><br><span class="line"> posdesc = <span class="string">"天苍苍,野茫茫,风吹草低见牛羊。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"辽宁省"</span>:</span><br><span class="line"> posdesc = <span class="string">"我想吃烤鸡架!"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"吉林省"</span>:</span><br><span class="line"> posdesc = <span class="string">"状元阁就是东北烧烤之王。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"黑龙江省"</span>:</span><br><span class="line"> posdesc = <span class="string">"很喜欢哈尔滨大剧院。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"上海市"</span>:</span><br><span class="line"> posdesc = <span class="string">"众所周知,中国只有两个城市。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"江苏省"</span>:</span><br><span class="line"> <span class="keyword">switch</span> (ipLoacation.<span class="property">city</span>) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"南京"</span>:</span><br><span class="line"> posdesc = <span class="string">"这是我挺想去的城市啦。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"苏州"</span>:</span><br><span class="line"> posdesc = <span class="string">"上有天堂,下有苏杭。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="attr">default</span>:</span><br><span class="line"> posdesc = <span class="string">"散装是必须要散装的。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"浙江省"</span>:</span><br><span class="line"> posdesc = <span class="string">"东风渐绿西湖柳,雁已还人未南归。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"河南省"</span>:</span><br><span class="line"> <span class="keyword">switch</span> (ipLoacation.<span class="property">city</span>) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"郑州"</span>:</span><br><span class="line"> posdesc = <span class="string">"豫州之域,天地之中。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"南阳"</span>:</span><br><span class="line"> posdesc = <span class="string">"臣本布衣,躬耕于南阳。此南阳非彼南阳!"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"驻马店"</span>:</span><br><span class="line"> posdesc = <span class="string">"峰峰有奇石,石石挟仙气。嵖岈山的花很美哦!"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"开封"</span>:</span><br><span class="line"> posdesc = <span class="string">"刚正不阿包青天。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"洛阳"</span>:</span><br><span class="line"> posdesc = <span class="string">"洛阳牡丹甲天下。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="attr">default</span>:</span><br><span class="line"> posdesc = <span class="string">"可否带我品尝河南烩面啦?"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"安徽省"</span>:</span><br><span class="line"> posdesc = <span class="string">"蚌埠住了,芜湖起飞。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"福建省"</span>:</span><br><span class="line"> posdesc = <span class="string">"井邑白云间,岩城远带山。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"江西省"</span>:</span><br><span class="line"> posdesc = <span class="string">"落霞与孤鹜齐飞,秋水共长天一色。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"山东省"</span>:</span><br><span class="line"> posdesc = <span class="string">"遥望齐州九点烟,一泓海水杯中泻。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"湖北省"</span>:</span><br><span class="line"> posdesc = <span class="string">"来碗热干面!"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"湖南省"</span>:</span><br><span class="line"> posdesc = <span class="string">"74751,长沙斯塔克。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"广东省"</span>:</span><br><span class="line"> posdesc = <span class="string">"老板来两斤福建人。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"广西壮族自治区"</span>:</span><br><span class="line"> posdesc = <span class="string">"桂林山水甲天下。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"海南省"</span>:</span><br><span class="line"> posdesc = <span class="string">"朝观日出逐白浪,夕看云起收霞光。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"四川省"</span>:</span><br><span class="line"> posdesc = <span class="string">"康康川妹子。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"贵州省"</span>:</span><br><span class="line"> posdesc = <span class="string">"茅台,学生,再塞200。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"云南省"</span>:</span><br><span class="line"> posdesc = <span class="string">"玉龙飞舞云缠绕,万仞冰川直耸天。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"西藏自治区"</span>:</span><br><span class="line"> posdesc = <span class="string">"躺在茫茫草原上,仰望蓝天。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"陕西省"</span>:</span><br><span class="line"> posdesc = <span class="string">"来份臊子面加馍。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"甘肃省"</span>:</span><br><span class="line"> posdesc = <span class="string">"羌笛何须怨杨柳,春风不度玉门关。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"青海省"</span>:</span><br><span class="line"> posdesc = <span class="string">"牛肉干和老酸奶都好好吃。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"宁夏回族自治区"</span>:</span><br><span class="line"> posdesc = <span class="string">"大漠孤烟直,长河落日圆。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"新疆维吾尔自治区"</span>:</span><br><span class="line"> posdesc = <span class="string">"驼铃古道丝绸路,胡马犹闻唐汉风。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"台湾省"</span>:</span><br><span class="line"> posdesc = <span class="string">"我在这头,大陆在那头。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"香港特别行政区"</span>:</span><br><span class="line"> posdesc = <span class="string">"永定贼有残留地鬼嚎,迎击光非岁玉。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"澳门特别行政区"</span>:</span><br><span class="line"> posdesc = <span class="string">"性感荷官,在线发牌。"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="attr">default</span>:</span><br><span class="line"> posdesc = <span class="string">"带我去你的城市逛逛吧!"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="attr">default</span>:</span><br><span class="line"> posdesc = <span class="string">"带我去你的国家逛逛吧。Show me around your country."</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//根据本地时间切换欢迎语</span></span><br><span class="line"> <span class="keyword">let</span> timeChange;</span><br><span class="line"> <span class="keyword">let</span> date = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line"> <span class="keyword">if</span> (date.<span class="title function_">getHours</span>() >= <span class="number">5</span> && date.<span class="title function_">getHours</span>() < <span class="number">11</span>) timeChange = <span class="string">"<span>上午好</span>,一日之计在于晨!"</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (date.<span class="title function_">getHours</span>() >= <span class="number">11</span> && date.<span class="title function_">getHours</span>() < <span class="number">13</span>) timeChange = <span class="string">"<span>中午好</span>,该摸鱼吃午饭了。"</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (date.<span class="title function_">getHours</span>() >= <span class="number">13</span> && date.<span class="title function_">getHours</span>() < <span class="number">15</span>) timeChange = <span class="string">"<span>下午好</span>,懒懒地睡个午觉吧!"</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (date.<span class="title function_">getHours</span>() >= <span class="number">15</span> && date.<span class="title function_">getHours</span>() < <span class="number">16</span>) timeChange = <span class="string">"<span>三点几啦</span>,一起饮茶呀!"</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (date.<span class="title function_">getHours</span>() >= <span class="number">16</span> && date.<span class="title function_">getHours</span>() < <span class="number">19</span>) timeChange = <span class="string">"<span>夕阳无限好!</span>"</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (date.<span class="title function_">getHours</span>() >= <span class="number">19</span> && date.<span class="title function_">getHours</span>() < <span class="number">24</span>) timeChange = <span class="string">"<span>晚上好</span>,夜生活嗨起来!"</span>;</span><br><span class="line"> <span class="keyword">else</span> timeChange = <span class="string">"夜深了,早点休息,少熬夜。"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//自定义文本和需要放的位置</span></span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"welcome-info"</span>).<span class="property">innerHTML</span> =</span><br><span class="line"> <span class="string">`<b><center>🎉 欢迎信息 🎉</center>&emsp;&emsp;欢迎来自 <span style="color:var(--theme-color)"><span class="subst">${pos}</span></span> 的小伙伴,<span class="subst">${timeChange}</span>您现在距离站长约 <span style="color:var(--theme-color)"><span class="subst">${dist}</span></span> 公里,当前的IP地址为: <span style="color:var(--theme-color)"><span class="subst">${ip}</span></span>, <span class="subst">${posdesc}</span></b>`</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Pjax无法获取#welcome-info元素🙄🙄🙄"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="variable language_">window</span>.<span class="property">onload</span> = showWelcome;</span><br><span class="line"><span class="comment">// 如果使用了pjax在加上下面这行代码</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">'pjax:complete'</span>, showWelcome);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="FPS检测(Ariasaka)"><a href="#FPS检测(Ariasaka)" class="headerlink" title="FPS检测(Ariasaka)"></a>FPS检测(Ariasaka)</h3><p><a href="https://blog.yaria.top/posts/670e47f/">博客魔改日记(3) | Ariasakaの小窝 (yaria.top)</a></p><h3 id="综合美化窗口"><a href="#综合美化窗口" class="headerlink" title="综合美化窗口"></a>综合美化窗口</h3><p><a href="https://www.fomal.cc/posts/9ac969bb.html">综合美化模块教程 | Fomalhaut🥝</a></p><p>Fomal参考了Leonus的教程,但是<del>还是Fomal的更全面</del>,所以用了Fomal的</p><p>但是有一个问题,Fomal他使用了自定义图标,按他的导航栏来,安知鱼图标不适配,于是<code>nav.pug</code>下面的部分改成这样:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">#menus</span><br><span class="line"> !=partial('includes/header/menu_item', {}, {cache: true})</span><br><span class="line"> #nav-right</span><br><span class="line"> if theme.nav.travelling</span><br><span class="line"> .nav-button.only-home#travellings_button(title='随机前往一个开往项目网站')</span><br><span class="line"> a.site-page(onclick='anzhiyu.totraveling()', title='随机前往一个开往项目网站', href='javascript:void(0);', rel='external nofollow', data-pjax-state='external')</span><br><span class="line"> i.anzhiyufont.anzhiyu-icon-train</span><br><span class="line"> .nav-button#randomPost_button</span><br><span class="line"> a.site-page(onclick='toRandomPost()', title='随机前往一个文章', href='javascript:void(0);')</span><br><span class="line"> i.anzhiyufont.anzhiyu-icon-dice</span><br><span class="line"> if (theme.algolia_search.enable || theme.local_search.enable || theme.docsearch.enable)</span><br><span class="line"> div.nav-button#search-button</span><br><span class="line"> a.site-page.social-icon.search(href='javascript:void(0);', title='搜索🔍' accesskey="s")</span><br><span class="line"> i.anzhiyufont.anzhiyu-icon-magnifying-glass</span><br><span class="line"> span=' '+_p('search.title')</span><br><span class="line"> </span><br><span class="line"> //- 美化设置开始</span><br><span class="line"> div.nav-button</span><br><span class="line"> a.meihua.faa-parent.animated-hover(onclick="toggleWinbox()" title="美化设置-自定义你的风格" id="meihua-button" )</span><br><span class="line"> i.anzhiyufont.anzhiyu-icon-pencil</span><br><span class="line"> //- 修改结束</span><br><span class="line"> if theme.centerConsole.enable</span><br><span class="line"> input#center-console(type="checkbox")</span><br><span class="line"> label.widget(for="center-console" title=_p("中控台") onclick="anzhiyu.switchConsole();")</span><br><span class="line"> i.left</span><br><span class="line"> i.widget.center</span><br><span class="line"> i.widget.right</span><br><span class="line"></span><br><span class="line"> !=partial('includes/anzhiyu/console', {}, {cache:true})</span><br><span class="line"></span><br><span class="line"> div.nav-button#nav-totop</span><br><span class="line"> a.totopbtn(href='javascript:void(0);')</span><br><span class="line"> i.anzhiyufont.anzhiyu-icon-arrow-up</span><br><span class="line"> span#percent(onclick="anzhiyu.scrollToDest(0,500)") 0</span><br><span class="line"></span><br><span class="line"> #toggle-menu</span><br><span class="line"> a.site-page(href='javascript:void(0);' title="切换")</span><br><span class="line"> i.anzhiyufont.anzhiyu-icon-bars</span><br></pre></td></tr></table></figure><h3 id="粒子连线-鼠标交互特效"><a href="#粒子连线-鼠标交互特效" class="headerlink" title="粒子连线+鼠标交互特效"></a>粒子连线+鼠标交互特效</h3><p>首先,感谢<a href="www.ordchaos.com">序炁</a>给的<code>canvas-nest-mouse.min.js</code>(我也不清楚原作者是谁,但是是他给我的)</p><p>把它外链引入就可以了,这是JS代码:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">!<span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">function</span> <span class="title function_">o</span>(<span class="params">w, v, i</span>) {</span><br><span class="line"> <span class="keyword">return</span> w.<span class="title function_">getAttribute</span>(v) || i</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">function</span> <span class="title function_">j</span>(<span class="params">i</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(i)</span><br><span class="line"> } <span class="keyword">function</span> <span class="title function_">l</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">var</span> i = <span class="title function_">j</span>(<span class="string">"script"</span>), w = i.<span class="property">length</span>, v = i[w - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">l</span>: w, <span class="attr">z</span>: <span class="title function_">o</span>(v, <span class="string">"zIndex"</span>, -<span class="number">1</span>), <span class="attr">o</span>: <span class="title function_">o</span>(v, <span class="string">"opacity"</span>, <span class="number">0.5</span>), <span class="attr">c</span>: <span class="title function_">o</span>(v, <span class="string">"color"</span>, <span class="string">"0,0,0"</span>), <span class="attr">n</span>: <span class="title function_">o</span>(v, <span class="string">"count"</span>, <span class="number">500</span>) } <span class="comment">/*经研究,发现count是粒子的数量,不要调太多,不然会粒子泛滥*/</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">function</span> <span class="title function_">k</span>(<span class="params"></span>) {</span><br><span class="line"> r = u.<span class="property">width</span> = <span class="variable language_">window</span>.<span class="property">innerWidth</span> || <span class="variable language_">document</span>.<span class="property">documentElement</span>.<span class="property">clientWidth</span> || <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">clientWidth</span>, n = u.<span class="property">height</span> = <span class="variable language_">window</span>.<span class="property">innerHeight</span> || <span class="variable language_">document</span>.<span class="property">documentElement</span>.<span class="property">clientHeight</span> || <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">clientHeight</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">function</span> <span class="title function_">b</span>(<span class="params"></span>) {</span><br><span class="line"> e.<span class="title function_">clearRect</span>(<span class="number">0</span>, <span class="number">0</span>, r, n);</span><br><span class="line"> <span class="keyword">var</span> w = [f].<span class="title function_">concat</span>(t);</span><br><span class="line"> <span class="keyword">var</span> x, v, A, B, z, y;</span><br><span class="line"> t.<span class="title function_">forEach</span>(<span class="keyword">function</span> (<span class="params">i</span>) {</span><br><span class="line"> i.<span class="property">x</span> += i.<span class="property">xa</span>, i.<span class="property">y</span> += i.<span class="property">ya</span>, i.<span class="property">xa</span> *= i.<span class="property">x</span> > r || i.<span class="property">x</span> < <span class="number">0</span> ? -<span class="number">1</span> : <span class="number">1</span>, i.<span class="property">ya</span> *= i.<span class="property">y</span> > n || i.<span class="property">y</span> < <span class="number">0</span> ? -<span class="number">1</span> : <span class="number">1</span>, e.<span class="title function_">fillRect</span>(i.<span class="property">x</span> - <span class="number">0.5</span>, i.<span class="property">y</span> - <span class="number">0.5</span>, <span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (v = <span class="number">0</span>; v < w.<span class="property">length</span>; v++) {</span><br><span class="line"> x = w[v];</span><br><span class="line"> <span class="keyword">if</span> (i !== x && <span class="literal">null</span> !== x.<span class="property">x</span> && <span class="literal">null</span> !== x.<span class="property">y</span>) {</span><br><span class="line"> B = i.<span class="property">x</span> - x.<span class="property">x</span>, z = i.<span class="property">y</span> - x.<span class="property">y</span>, y = B * B + z * z;</span><br><span class="line"> y < x.<span class="property">max</span> && (x === f && y >= x.<span class="property">max</span> / <span class="number">2</span> && (i.<span class="property">x</span> -= <span class="number">0.03</span> * B, i.<span class="property">y</span> -= <span class="number">0.03</span> * z), A = (x.<span class="property">max</span> - y) / x.<span class="property">max</span>, e.<span class="title function_">beginPath</span>(), e.<span class="property">lineWidth</span> = A / <span class="number">2</span>, e.<span class="property">strokeStyle</span> = <span class="string">"rgba("</span> + s.<span class="property">c</span> + <span class="string">","</span> + (A + <span class="number">0.2</span>) + <span class="string">")"</span>, e.<span class="title function_">moveTo</span>(i.<span class="property">x</span>, i.<span class="property">y</span>), e.<span class="title function_">lineTo</span>(x.<span class="property">x</span>, x.<span class="property">y</span>), e.<span class="title function_">stroke</span>())</span><br><span class="line"> }</span><br><span class="line"> } w.<span class="title function_">splice</span>(w.<span class="title function_">indexOf</span>(i), <span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> }), <span class="title function_">m</span>(b)</span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">var</span> u = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">"canvas"</span>), s = <span class="title function_">l</span>(), c = <span class="string">"c_n"</span> + s.<span class="property">l</span>, e = u.<span class="title function_">getContext</span>(<span class="string">"2d"</span>), r, n, m = <span class="variable language_">window</span>.<span class="property">requestAnimationFrame</span> || <span class="variable language_">window</span>.<span class="property">webkitRequestAnimationFrame</span> || <span class="variable language_">window</span>.<span class="property">mozRequestAnimationFrame</span> || <span class="variable language_">window</span>.<span class="property">oRequestAnimationFrame</span> || <span class="variable language_">window</span>.<span class="property">msRequestAnimationFrame</span> || <span class="keyword">function</span> (<span class="params">i</span>) { <span class="variable language_">window</span>.<span class="built_in">setTimeout</span>(i, <span class="number">1000</span> / <span class="number">45</span>) }, a = <span class="title class_">Math</span>.<span class="property">random</span>, f = { <span class="attr">x</span>: <span class="literal">null</span>, <span class="attr">y</span>: <span class="literal">null</span>, <span class="attr">max</span>: <span class="number">20000</span> };</span><br><span class="line"> u.<span class="property">id</span> = c;</span><br><span class="line"> u.<span class="property">className</span>=<span class="string">"lizicanvas"</span>;<span class="comment">/*为了方便开关粒子特效,自己给粒子的canvas加了一个类*/</span></span><br><span class="line"> u.<span class="property">style</span>.<span class="property">cssText</span> = <span class="string">"position:fixed;top:0;left:0;z-index:"</span> + s.<span class="property">z</span> + <span class="string">";opacity:"</span> + s.<span class="property">o</span>;</span><br><span class="line"> <span class="title function_">j</span>(<span class="string">"body"</span>)[<span class="number">0</span>].<span class="title function_">appendChild</span>(u);</span><br><span class="line"> <span class="title function_">k</span>(), <span class="variable language_">window</span>.<span class="property">onresize</span> = k;</span><br><span class="line"> <span class="variable language_">window</span>.<span class="property">onmousemove</span> = <span class="keyword">function</span> (<span class="params">i</span>) { i = i || <span class="variable language_">window</span>.<span class="property">event</span>, f.<span class="property">x</span> = i.<span class="property">clientX</span>, f.<span class="property">y</span> = i.<span class="property">clientY</span> }, <span class="variable language_">window</span>.<span class="property">onmouseout</span> = <span class="keyword">function</span> (<span class="params"></span>) { f.<span class="property">x</span> = <span class="literal">null</span>, f.<span class="property">y</span> = <span class="literal">null</span> };</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> t = [], p = <span class="number">0</span>;s.<span class="property">n</span> > p;p++) {</span><br><span class="line"> <span class="keyword">var</span> h = <span class="title function_">a</span>() * r, g = <span class="title function_">a</span>() * n, q = <span class="number">2</span> * <span class="title function_">a</span>() - <span class="number">1</span>, d = <span class="number">2</span> * <span class="title function_">a</span>() - <span class="number">1</span>;</span><br><span class="line"> t.<span class="title function_">push</span>({ <span class="attr">x</span>: h, <span class="attr">y</span>: g, <span class="attr">xa</span>: q, <span class="attr">ya</span>: d, <span class="attr">max</span>: <span class="number">6000</span> })</span><br><span class="line"> } </span><br><span class="line"> <span class="built_in">setTimeout</span>(<span class="keyword">function</span> (<span class="params"></span>) { <span class="title function_">b</span>() }, <span class="number">100</span>);</span><br><span class="line">}();</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>好了,写了这么多,全是链接,下期写评论等系统的部署经验,拜拜。</p>]]></content>
<summary type="html"><h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>上次,我们完成了Hexo框架的搭建。这次,我讲如何美化博客。</p>
<p>一打开博客页面,是一个单调的LandScape主题,没有首页,还有一篇hello world的英文文章。</p>
<p>想自己装饰那么多肯定不容易,于是我们就要去<a href="ht</summary>
<category term="Hexo" scheme="https://blog.qyadbr.top/categories/Hexo/"/>
<category term="Hexo" scheme="https://blog.qyadbr.top/tags/Hexo/"/>
<category term="建站" scheme="https://blog.qyadbr.top/tags/%E5%BB%BA%E7%AB%99/"/>
<category term="免费" scheme="https://blog.qyadbr.top/tags/%E5%85%8D%E8%B4%B9/"/>
</entry>
<entry>
<title>Hexo博客0氪建站记录(上)</title>
<link href="https://blog.qyadbr.top/posts/hexo1/"/>
<id>https://blog.qyadbr.top/posts/hexo1/</id>
<published>2024-08-23T03:00:56.000Z</published>
<updated>2025-05-28T13:03:14.469Z</updated>
<content type="html"><![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>大家好,我叫Admibrill,<del>建站十多天了,没有发过一次文章</del>。</p><p>第一篇文章,我决定记录一下我个人的建站历程。</p><h2 id="各种环境依赖的安装"><a href="#各种环境依赖的安装" class="headerlink" title="各种环境依赖的安装"></a>各种环境依赖的安装</h2><p>跟着<a href="https://www.fomal.cc/posts/e593433d.html">Fomal大佬的教程</a>,我开始了建站。 </p><h3 id="Github账号和仓库"><a href="#Github账号和仓库" class="headerlink" title="Github账号和仓库"></a>Github账号和仓库</h3><p>我本来就有一个github的账号,于是建了个仓库叫<code>admibrill.github.io</code>。</p><p>使用<code>Github Pages</code>的源文件仓库要命名为<code><username>.github.io</code>。</p><p>这代表网站源码要通过github托管,会使用<code>Github Pages</code>部署,别人可以通过<code>https://admibrill.github.io</code>来访问我的网站。</p><h3 id="本地源文件存储文件夹"><a href="#本地源文件存储文件夹" class="headerlink" title="本地源文件存储文件夹"></a>本地源文件存储文件夹</h3><p>在你喜欢的位置,建一个文件夹,起一个喜欢的名字(建议不要有汉字)。</p><p>不同的人起的名字不同,这个文件夹就用<code>[blogroot]</code>来指代。</p><h3 id="node-js和git的安装"><a href="#node-js和git的安装" class="headerlink" title="node.js和git的安装"></a>node.js和git的安装</h3><p><a href="https://nodejs.org/en/download/">https://nodejs.org/en/download/</a></p><p><a href="https://git-scm.com/downloads">Git - Downloads (git-scm.com)</a></p><p>下载安装之后,打开<code>[blogroot]</code>,右键单击空白处,即可发现菜单中多出来了<code>Git Bash Here</code>一项</p><p> <img src="https://image.m-c.top/?/images/2024/08/23/NuXMqVMoUZ/1111.png" alt=""> </p><p>打开它,然后后面的很多命令都使用bash输入。</p><h3 id="Hexo的安装"><a href="#Hexo的安装" class="headerlink" title="Hexo的安装"></a>Hexo的安装</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g hexo-cli</span><br></pre></td></tr></table></figure><p>然后,因为我是第一次使用,配置用户名和邮箱</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global user.name <span class="string">"<your username>"</span></span><br><span class="line">git config --global user.email <span class="string">"<your email>"</span></span><br></pre></td></tr></table></figure><h3 id="连接至github"><a href="#连接至github" class="headerlink" title="连接至github"></a>连接至github</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -C <span class="string">"<your email>"</span></span><br></pre></td></tr></table></figure><h2 id="Hexo,启动!!!"><a href="#Hexo,启动!!!" class="headerlink" title="Hexo,启动!!!"></a>Hexo,启动!!!</h2><h3 id="初始化Hexo"><a href="#初始化Hexo" class="headerlink" title="初始化Hexo"></a>初始化Hexo</h3><p>打开<code>[blogroot]</code>,右键选择‘<code>Git bash here</code>。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo init</span><br></pre></td></tr></table></figure><p>这时,我们的<code>[blogroot]</code>中缓缓出现了很多文件。</p><p>Hexo会自动安装依赖包。</p><p>等待程序执行完成,命令行中会出现一句<code>Start blogging with Hexo!</code>就代表Hexo初始化成功了。</p><h3 id="安装挂载依赖包"><a href="#安装挂载依赖包" class="headerlink" title="安装挂载依赖包"></a>安装挂载依赖包</h3><p>有一个包Hexo不会自动安装,叫做<code>hexo-deployer-git</code>。</p><p>我们就要使用npm的安装命令安装它(以后安装一些包通用)。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-deployer-git --save</span><br></pre></td></tr></table></figure><p>等待运行完成就好了。</p><h3 id="修改配置文件"><a href="#修改配置文件" class="headerlink" title="修改配置文件"></a>修改配置文件</h3><p>打开<code>[blogroot]</code>目录下的<code>_config.yml</code>文件,修改以下设置:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">url:</span> <span class="string">https://<your</span> <span class="string">username>.github.io</span></span><br><span class="line"><span class="attr">root:</span> <span class="string">/</span></span><br></pre></td></tr></table></figure><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">deploy:</span></span><br><span class="line"><span class="attr">type:</span> <span class="string">git</span></span><br><span class="line"><span class="attr">repository:</span> <span class="string">https://github.com/<your</span> <span class="string">username>/<your</span> <span class="string">username>.github.io.git</span></span><br></pre></td></tr></table></figure><h3 id="挂载博客到Github-Pages"><a href="#挂载博客到Github-Pages" class="headerlink" title="挂载博客到Github Pages"></a>挂载博客到Github Pages</h3><p>常用运行命令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo cl</span><br></pre></td></tr></table></figure><p>这个命令用于清除之前生成的静态文件。第一次没有生成,所以不用</p><p>后面只要使用了<code>hexo g</code>就一定要使用,因为<code>hexo g</code>不会把之前生成过的文件再生成一遍,在<code>hexo g</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo g</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo d</span><br></pre></td></tr></table></figure><p>这样,我们就把网站上传了,如果你想在本地预览,就运行如下命令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo s</span><br></pre></td></tr></table></figure><p>这些就是常用命令。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>我通过这样的方式建立了这样的一个个人空间。</p><p>我知道网上有很多这样的教程,但是这是我的个人经验,总体上还是能算原创的,再次感谢<a href="https://www.fomal.cc/posts/e593433d.html">Fomal大佬的教程</a>。</p><p>下一篇,我讲讲关于博客的美化。886!</p>]]></content>
<summary type="html"><h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>大家好,我叫Admibrill,<del>建站十多天了,没有发过一次文章</del>。</p>
<p>第一篇文章,我决定记录一下我个人的建站历程。</p>
<h2 id="各种环境依赖的安装"><a href="#各种环境依赖的安装" class="heade</summary>
<category term="Hexo" scheme="https://blog.qyadbr.top/categories/Hexo/"/>
<category term="Hexo" scheme="https://blog.qyadbr.top/tags/Hexo/"/>
<category term="建站" scheme="https://blog.qyadbr.top/tags/%E5%BB%BA%E7%AB%99/"/>
<category term="免费" scheme="https://blog.qyadbr.top/tags/%E5%85%8D%E8%B4%B9/"/>
</entry>
</feed>