﻿<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Ming</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://iming.eu.org/</id>
  <link href="https://iming.eu.org/" rel="alternate"/>
  <link href="https://iming.eu.org/feed.xml" rel="self"/>
  <rights>All rights reserved 2026, Ming</rights>
  <subtitle>
    <![CDATA[Sit back & relax.]]>
  </subtitle>
  <title>进行时</title>
  <updated>2026-05-18T03:22:11.227Z</updated>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="效率工具" scheme="https://iming.eu.org/categories/%E6%95%88%E7%8E%87%E5%B7%A5%E5%85%B7/"/>
    <category term="Claude Code" scheme="https://iming.eu.org/tags/Claude-Code/"/>
    <category term="DeepSeek" scheme="https://iming.eu.org/tags/DeepSeek/"/>
    <category term="CC Switch" scheme="https://iming.eu.org/tags/CC-Switch/"/>
    <category term="AI 编程" scheme="https://iming.eu.org/tags/AI-%E7%BC%96%E7%A8%8B/"/>
    <content>
      <![CDATA[<blockquote><p><strong>当前 deepseek-v4-pro 模型 2.5 折，优惠期延长至北京时间 2026&#x2F;05&#x2F;31 23:59</strong></p><p>DeepSeek-V4-Pro 限时2.5折，我啪一下，很快啊，直接就去 Claude Code 接入 DeepSeek-V4-Pro 了 <del>梁圣还是太伟大了</del></p></blockquote><h2 id="基础环境配置"><a href="#基础环境配置" class="headerlink" title="基础环境配置"></a>基础环境配置</h2><h3 id="安装-Claude-Code"><a href="#安装-Claude-Code" class="headerlink" title="安装 Claude Code"></a>安装 Claude Code</h3><p><code>Claude Code</code> 是 Anthropic 推出的终端原生 AI 编程助手。在使用之前，需要确保系统中已安装 Node.js。</p><p>打开终端并运行以下命令进行全局安装：</p><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">安装 Claude Code 全局依赖</span></span><br><span class="line">npm install -g @anthropic-ai/claude-code</span><br></pre></td></tr></table></figure><p>安装完成后，可以通过 claude 命令验证是否成功。</p><h3 id="安装-CC-Switch"><a href="#安装-CC-Switch" class="headerlink" title="安装 CC Switch"></a>安装 CC Switch</h3><p>要在不侵入修改 Claude Code 底层代码的情况下优雅地切换模型，需要用到 <code>cc-switch</code>。这是一款跨平台的桌面端全能 AI 助手管理工具，可以一键劫持并代理相关终端工具的请求。</p><p>请直接前往项目的官方 GitHub Releases 页面，获取最新版软件：</p><p>🔗 <strong><a href="https://github.com/farion1231/cc-switch/releases">CC Switch Releases 下载地址</a></strong></p><p>根据你的操作系统（Windows &#x2F; macOS &#x2F; Linux）下载对应的安装包并正常安装。安装完成后，启动该软件。</p><p><a class="pswp-link" href="/2026/05/15/cc-deepseek-v4-pro/main-en.large.webp" data-pswp-width="1878" data-pswp-height="1252" target="_blank" rel="noopener"><img src="/2026/05/15/cc-deepseek-v4-pro/main-en.thumb.webp" width="1280" height="853" alt="main" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2026/05/15/cc-deepseek-v4-pro/add-en.large.webp" data-pswp-width="1980" data-pswp-height="1290" target="_blank" rel="noopener"><img src="/2026/05/15/cc-deepseek-v4-pro/add-en.thumb.webp" width="1280" height="834" alt="add" loading="lazy" decoding="async"></a></p><hr><h2 id="配置-DeepSeek-V4-Pro-节点"><a href="#配置-DeepSeek-V4-Pro-节点" class="headerlink" title="配置 DeepSeek-V4-Pro 节点"></a>配置 DeepSeek-V4-Pro 节点</h2><p>打开 CC Switch 后，我们需要将 DeepSeek 作为一个新的 Provider（模型提供商）添加进去。</p><p><a class="pswp-link" href="/2026/05/15/cc-deepseek-v4-pro/cc-switch-1.large.webp" data-pswp-width="975" data-pswp-height="655" target="_blank" rel="noopener"><img src="/2026/05/15/cc-deepseek-v4-pro/cc-switch-1.thumb.webp" width="975" height="655" alt="cc-switch-1" loading="lazy" decoding="async"></a></p><ol><li>在 CC Switch 的主界面，点击右上角或侧边栏的 <strong>Add Provider</strong>（添加服务商）。</li><li>在弹出的配置类型中，选择 <strong>Custom</strong>（自定义配置）。</li><li>按照以下参数填入 DeepSeek 的相关信息：<ul><li><strong>Provider Name</strong>: <code>DeepSeek-V4</code> (可自定义，用于区分)</li><li><strong>Model</strong>: <code>deepseek-v4-pro</code>（请确保模型名称填写准确）</li><li><strong>Base URL</strong>: <code>https://api.deepseek.com/anthropic</code></li><li><strong>API Key</strong>: 填入你在 DeepSeek 开放平台申请到的 API Key。</li></ul></li><li>点击 <strong>Save</strong> 保存配置，返回主界面在 <code>Claude</code>选项卡下方启用配置即可 。</li></ol><p><a class="pswp-link" href="/2026/05/15/cc-deepseek-v4-pro/cc-switch-2.large.webp" data-pswp-width="1229" data-pswp-height="878" target="_blank" rel="noopener"><img src="/2026/05/15/cc-deepseek-v4-pro/cc-switch-2.thumb.webp" width="1229" height="878" alt="cc-switch-2" loading="lazy" decoding="async"></a></p><hr><h2 id="重启并在终端运行"><a href="#重启并在终端运行" class="headerlink" title="重启并在终端运行"></a>重启并在终端运行</h2><p>为了让代理配置彻底生效，<strong>请务必重启你的终端窗口（Terminal）</strong>。</p><p>然后，切换到你的代码项目目录下，像往常一样唤醒 Claude Code：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Claude</span><br></pre></td></tr></table></figure><p>就可以愉快的在 Claude Code 中使用 DeepSeek 了。</p><hr><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><p>需要注意，即使在 CC Switch 的配置中开启了“最大强度思考”（对应 JSON 字段 <code>&quot;effortLevel&quot;: &quot;max&quot;</code>），在终端中首次启动 Claude Code 时，默认加载的仍是 <strong>200k 上下文</strong> 版本的 DeepSeek V4 Pro。</p><p><a class="pswp-link" href="/2026/05/15/cc-deepseek-v4-pro/cc-1.large.webp" data-pswp-width="1224" data-pswp-height="688" target="_blank" rel="noopener"><img src="/2026/05/15/cc-deepseek-v4-pro/cc-1.thumb.webp" width="1224" height="688" alt="默认加载的模型为 200k 上下文版本" loading="lazy" decoding="async"></a></p><p>如果需要用到 <strong>1M 的超长上下文</strong>，只需在 Claude Code 中输入 <code>/model</code>，然后手动切换至 <code>deepseek-v4-pro[1m]</code> 即可。</p><p><a class="pswp-link" href="/2026/05/15/cc-deepseek-v4-pro/cc-2.large.webp" data-pswp-width="1224" data-pswp-height="688" target="_blank" rel="noopener"><img src="/2026/05/15/cc-deepseek-v4-pro/cc-2.thumb.webp" width="1224" height="688" alt="通过 &amp;#x2F;model 命令切换至 1M 上下文版本" loading="lazy" decoding="async"></a></p>]]>
    </content>
    <id>https://iming.eu.org/2026/05/15/cc-deepseek-v4-pro/</id>
    <link href="https://iming.eu.org/2026/05/15/cc-deepseek-v4-pro/"/>
    <published>2026-05-15T07:00:00.000Z</published>
    <summary>在 Claude Code 中无缝配置并使用高性价比的 DeepSeek-V4-Pro 模型。</summary>
    <title>Claude Code 接入 DeepSeek-V4-Pro 小记</title>
    <updated>2026-05-18T03:22:11.227Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="VPS" scheme="https://iming.eu.org/categories/VPS/"/>
    <category term="DailyHotApi" scheme="https://iming.eu.org/tags/DailyHotApi/"/>
    <category term="Docker" scheme="https://iming.eu.org/tags/Docker/"/>
    <category term="RSS" scheme="https://iming.eu.org/tags/RSS/"/>
    <content>
      <![CDATA[<blockquote><p>今日热榜 API，一个聚合热门数据的 <a href="https://github.com/imsyy/DailyHotApi?tab=readme-ov-file">API 接口</a>，支持 RSS 模式 及 Vercel 部署，并含有配套的<a href="https://github.com/imsyy/DailyHot">前端项目</a>。</p></blockquote><h2 id="拉取项目"><a href="#拉取项目" class="headerlink" title="拉取项目"></a>拉取项目</h2><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 <span class="built_in">clone</span> https://github.com/imsyy/DailyHotApi.git</span><br><span class="line"><span class="built_in">cd</span> DailyHotApi</span><br></pre></td></tr></table></figure><h2 id="安装依赖"><a href="#安装依赖" class="headerlink" title="安装依赖"></a>安装依赖</h2><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</span><br></pre></td></tr></table></figure><h2 id="修改配置"><a href="#修改配置" class="headerlink" title="修改配置"></a>修改配置</h2><p>复制 <code>/.env.example</code> 文件并重命名为 <code>/.env</code> 并修改配置，包括<code>Redis</code>端口密码等</p><figure class="highlight bash"><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><br><span class="line"><span class="comment"># 允许的域名</span></span><br><span class="line">ALLOWED_DOMAIN = <span class="string">&quot;*&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 允许的主域名，填写格式为 imsyy.top</span></span><br><span class="line"><span class="comment">## 若填写该项，将忽略 ALLOWED_DOMAIN</span></span><br><span class="line">ALLOWED_HOST=<span class="string">&quot;jianbing.tk&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ROBOT</span></span><br><span class="line">DISALLOW_ROBOT = <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Redis</span></span><br><span class="line">REDIS_HOST=<span class="string">&quot;127.0.0.1&quot;</span></span><br><span class="line">REDIS_PORT=6379</span><br><span class="line">REDIS_PASSWORD=<span class="string">&quot;Your Password&quot;</span></span><br><span class="line">...</span><br></pre></td></tr></table></figure><h2 id="开发"><a href="#开发" class="headerlink" title="开发"></a>开发</h2><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 run dev</span><br></pre></td></tr></table></figure><p>成功启动后程序会在控制台输出可访问的地址</p><h2 id="编译运行"><a href="#编译运行" class="headerlink" title="编译运行"></a>编译运行</h2><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">npm run build</span><br><span class="line">npm run start</span><br></pre></td></tr></table></figure><p>成功启动后程序会在控制台输出可访问的地址</p><h2 id="自定义RSS订阅"><a href="#自定义RSS订阅" class="headerlink" title="自定义RSS订阅"></a>自定义RSS订阅</h2><p>自定义RSS订阅通常只要新增两个部分的内容：</p><p>1.<code>src\routes</code>路径下的<code>xxx.ts</code>文件，比如<code>nodeseek.ts</code>，用来处理与 <code>NodeSeek</code>相关的路由和数据获取逻辑。</p><p>2.<code>src\router.type.d.ts</code>文件中的特定数据结构的类型接口。例如，<code>&quot;36kr&quot;</code> 类型接口，在<code>36kr.ts</code>中使用：</p><figure class="highlight typescript"><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="keyword">return</span> &#123;</span><br><span class="line">    ...result,</span><br><span class="line">    <span class="attr">data</span>: list.<span class="title function_">map</span>(<span class="function">(<span class="params"><span class="attr">v</span>: <span class="title class_">RouterType</span>[<span class="string">&quot;36kr&quot;</span>]</span>) =&gt;</span> &#123; <span class="comment">//此处的RouterType</span></span><br><span class="line">      <span class="keyword">const</span> item = v.<span class="property">templateMaterial</span>;</span><br><span class="line">      <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">id</span>: v.<span class="property">itemId</span>,</span><br><span class="line">        <span class="attr">title</span>: item.<span class="property">widgetTitle</span>,</span><br><span class="line">        <span class="attr">cover</span>: item.<span class="property">widgetImage</span>,</span><br><span class="line">        <span class="attr">author</span>: item.<span class="property">authorName</span>,</span><br><span class="line">        <span class="attr">timestamp</span>: <span class="title function_">getTime</span>(v.<span class="property">publishTime</span>),</span><br><span class="line">        <span class="attr">hot</span>: item.<span class="property">statCollect</span> || <span class="literal">undefined</span>,</span><br><span class="line">        <span class="attr">url</span>: <span class="string">`https://www.36kr.com/p/<span class="subst">$&#123;v.itemId&#125;</span>`</span>,</span><br><span class="line">        <span class="attr">mobileUrl</span>: <span class="string">`https://m.36kr.com/p/<span class="subst">$&#123;v.itemId&#125;</span>`</span>,</span><br><span class="line">      &#125;;</span><br><span class="line">    &#125;),</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><hr><p>当然也可以不定义新的类型接口，只添加<code>xxx.ts</code>文件，借助<code>parseRSS</code>处理：</p><figure class="highlight typescript"><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">/* parseRSS.ts */</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">RSSParser</span> <span class="keyword">from</span> <span class="string">&quot;rss-parser&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> logger <span class="keyword">from</span> <span class="string">&quot;./logger.js&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 提取 RSS 内容</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> content HTML 内容</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@returns</span> RSS 内容</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> extractRss = (<span class="attr">content</span>: <span class="built_in">string</span>): <span class="built_in">string</span> | <span class="function"><span class="params">null</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 匹配 &lt;rss&gt; 标签及内容</span></span><br><span class="line">  <span class="keyword">const</span> rssRegex = <span class="regexp">/(&lt;rss[\s\S]*?&lt;\/rss&gt;)/i</span>;</span><br><span class="line">  <span class="keyword">const</span> matches = content.<span class="title function_">match</span>(rssRegex);</span><br><span class="line">  <span class="keyword">return</span> matches ? matches[<span class="number">0</span>] : <span class="literal">null</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 解析 RSS 内容</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> rssContent RSS 内容</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@returns</span> 解析后的 RSS 内容</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">parseRSS</span> = <span class="keyword">async</span> (<span class="params"><span class="attr">rssContent</span>: <span class="built_in">string</span></span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> parser = <span class="keyword">new</span> <span class="title class_">RSSParser</span>();</span><br><span class="line">  <span class="comment">// 是否为网址</span></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">isUrl</span> = (<span class="params"><span class="attr">url</span>: <span class="built_in">string</span></span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">new</span> <span class="title function_">URL</span>(url);</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> feed = <span class="title function_">isUrl</span>(rssContent)</span><br><span class="line">      ? <span class="keyword">await</span> parser.<span class="title function_">parseURL</span>(rssContent)</span><br><span class="line">      : <span class="keyword">await</span> parser.<span class="title function_">parseString</span>(rssContent);</span><br><span class="line">    <span class="keyword">const</span> items = feed.<span class="property">items</span>.<span class="title function_">map</span>(<span class="function">(<span class="params">item</span>) =&gt;</span> (&#123;</span><br><span class="line">      <span class="attr">title</span>: item.<span class="property">title</span>,</span><br><span class="line">      <span class="attr">link</span>: item.<span class="property">link</span>,</span><br><span class="line">      <span class="attr">pubDate</span>: item.<span class="property">pubDate</span>,</span><br><span class="line">      <span class="attr">author</span>: item.<span class="property">creator</span> ?? item.<span class="property">author</span>,</span><br><span class="line">      <span class="attr">content</span>: item.<span class="property">content</span>,</span><br><span class="line">      <span class="attr">contentSnippet</span>: item.<span class="property">contentSnippet</span>,</span><br><span class="line">      <span class="attr">guid</span>: item.<span class="property">guid</span>,</span><br><span class="line">      <span class="attr">categories</span>: item.<span class="property">categories</span>,</span><br><span class="line">    &#125;));</span><br><span class="line">    <span class="keyword">return</span> items;</span><br><span class="line">  &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">    logger.<span class="title function_">error</span>(<span class="string">&quot;❌ [RSS] An error occurred while parsing RSS content&quot;</span>);</span><br><span class="line">    <span class="keyword">throw</span> error;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>一般网站的<code>RSS</code>订阅都能借助<code>src\utils\parseRSS.ts</code>文件正确解析：</p><figure class="highlight typescript"><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="keyword">const</span> <span class="title function_">getList</span> = <span class="keyword">async</span> (<span class="params"><span class="attr">noCache</span>: <span class="built_in">boolean</span></span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> url = <span class="string">`https://rss.nodeseek.com/`</span>;</span><br><span class="line">  <span class="keyword">const</span> result = <span class="keyword">await</span> <span class="title function_">get</span>(&#123; url, noCache &#125;);</span><br><span class="line">  <span class="keyword">const</span> list = <span class="keyword">await</span> <span class="title function_">parseRSS</span>(result.<span class="property">data</span>);</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    ...result,</span><br><span class="line">    <span class="attr">data</span>: list.<span class="title function_">map</span>(<span class="function">(<span class="params">v, i</span>) =&gt;</span> (&#123;</span><br><span class="line">      <span class="attr">id</span>: v.<span class="property">guid</span> || i,</span><br><span class="line">      <span class="attr">title</span>: v.<span class="property">title</span> || <span class="string">&quot;&quot;</span>,</span><br><span class="line">      <span class="attr">desc</span>: v.<span class="property">content</span>?.<span class="title function_">trim</span>() || <span class="string">&quot;&quot;</span>,</span><br><span class="line">      <span class="attr">author</span>: v.<span class="property">author</span>,</span><br><span class="line">      <span class="attr">timestamp</span>: <span class="title function_">getTime</span>(v.<span class="property">pubDate</span> || <span class="number">0</span>),</span><br><span class="line">      <span class="attr">hot</span>: <span class="literal">undefined</span>,</span><br><span class="line">      <span class="attr">url</span>: v.<span class="property">link</span> || <span class="string">&quot;&quot;</span>,</span><br><span class="line">      <span class="attr">mobileUrl</span>: v.<span class="property">link</span> || <span class="string">&quot;&quot;</span>,</span><br><span class="line">    &#125;)),</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>部分订阅需要自己处理请求返回的数据，同时新增<code>RouterType</code>，且不借助<code>parseRSS</code>处理<code>result.data</code>：</p><figure class="highlight typescript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">getList</span> = <span class="keyword">async</span> (<span class="params"><span class="attr">options</span>: <span class="title class_">Options</span>, <span class="attr">noCache</span>: <span class="built_in">boolean</span></span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; <span class="keyword">type</span> &#125; = options;</span><br><span class="line">  <span class="keyword">const</span> url = <span class="string">`https://linux.do/<span class="subst">$&#123;<span class="keyword">type</span>&#125;</span>.json`</span>;</span><br><span class="line">  <span class="keyword">const</span> result = <span class="keyword">await</span> <span class="title function_">get</span>(&#123; url, noCache &#125;);</span><br><span class="line">  <span class="keyword">const</span> list = result.<span class="property">data</span>?.<span class="property">topic_list</span>?.<span class="property">topics</span>;</span><br><span class="line">  <span class="keyword">const</span> filteredIds = [<span class="number">5</span>, <span class="number">293017</span>, <span class="number">298988</span>];</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    <span class="attr">fromCache</span>: result.<span class="property">fromCache</span>,</span><br><span class="line">    <span class="attr">updateTime</span>: result.<span class="property">updateTime</span>,</span><br><span class="line">    <span class="attr">data</span>: list</span><br><span class="line">    .<span class="title function_">filter</span>(<span class="function">(<span class="params"><span class="attr">v</span>: <span class="title class_">RouterType</span>[<span class="string">&quot;linuxdo&quot;</span>]</span>) =&gt;</span> !filteredIds.<span class="title function_">includes</span>(v.<span class="property">id</span>))</span><br><span class="line">    .<span class="title function_">map</span>(<span class="function">(<span class="params"><span class="attr">v</span>: <span class="title class_">RouterType</span>[<span class="string">&quot;linuxdo&quot;</span>]</span>) =&gt;</span> (&#123;</span><br><span class="line">      <span class="attr">id</span>: v.<span class="property">id</span>,</span><br><span class="line">      <span class="attr">title</span>: v.<span class="property">title</span>,</span><br><span class="line">      <span class="attr">timestamp</span>: v.<span class="property">last_comment_at</span> || v.<span class="property">created_at</span>,</span><br><span class="line">      <span class="attr">hot</span>: v.<span class="property">highest_post_number</span>,</span><br><span class="line">      <span class="attr">url</span>: <span class="string">`https://linux.do/t/topic/<span class="subst">$&#123;v.id&#125;</span>`</span>,</span><br><span class="line">      <span class="attr">mobileUrl</span>: <span class="string">`https://linux.do/t/topic/<span class="subst">$&#123;v.id&#125;</span>`</span>,</span><br><span class="line">    &#125;)),</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>注意：除了自定义<code>RSS</code>订阅以外，还可以自行修改<code>DailyHotApi</code>项目的<code>icon</code>、页脚等信息，其中<code>Home.tsx</code>中的<code>&lt;img&gt;</code>标签中的图片为<code>base64</code>格式，需自行转码。</p><h2 id="Docker部署"><a href="#Docker部署" class="headerlink" title="Docker部署"></a>Docker部署</h2><p>将本地开发好的项目部署至自己的服务器</p><figure class="highlight bash"><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="comment"># 列出所有正在运行的容器</span></span><br><span class="line">docker ps</span><br><span class="line"></span><br><span class="line"><span class="comment"># 列出所有镜像，并筛选出名称包含 dailyhot-api 的镜像</span></span><br><span class="line">docker images | grep dailyhot-api</span><br><span class="line"></span><br><span class="line"><span class="comment"># 停止名为 dailyhot-api 的容器（可以使用容器名称或 ID）</span></span><br><span class="line">docker stop dailyhot-api</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除名为 dailyhot-api 的容器（可以使用容器名称或 ID）</span></span><br><span class="line">docker <span class="built_in">rm</span> dailyhot-api</span><br><span class="line"></span><br><span class="line"><span class="comment"># 构建镜像，使用当前目录的 Dockerfile，并将镜像命名为 dailyhot-api</span></span><br><span class="line">docker build -t dailyhot-api .</span><br><span class="line"></span><br><span class="line"><span class="comment"># 运行容器，设置自动重启，映射主机的 6688 端口到容器的 6688 端口，并在后台运行</span></span><br><span class="line">docker run --restart always -p 6688:6688 -d --name dailyhot-api dailyhot-api</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或使用 Docker Compose 启动服务，后台运行</span></span><br><span class="line">docker-compose up -d</span><br></pre></td></tr></table></figure><p>注意：原项目中包含<code>Redis</code>缓存配置，需与服务器中端口和密码保持一致。</p><p>此外，<code>Redis</code> 缓存时长默认为 3600 秒（即一小时），你可以在 <code>config.ts</code> 文件中通过修改环境变量 <code>CACHE_TTL</code> 的值来调整该时长。</p><h2 id="成品展示"><a href="#成品展示" class="headerlink" title="成品展示"></a>成品展示</h2><p><a class="pswp-link" href="/2025/01/14/dailyhotapi-rss/demo.large.webp" data-pswp-width="1685" data-pswp-height="900" target="_blank" rel="noopener"><img src="/2025/01/14/dailyhotapi-rss/demo.thumb.webp" width="1280" height="684" alt="Demo" loading="lazy" decoding="async"></a></p><blockquote><p>预览：<a href="https://hot.jianbing.tk/">神马值得看</a></p></blockquote><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://github.com/imsyy/DailyHot">DailyHot</a></li><li><a href="https://github.com/imsyy/DailyHotApi">DailyHotApi</a></li><li><a href="https://blog.imsyy.top/posts/2024/0408">blog.imsyy.top</a></li></ul>]]>
    </content>
    <id>https://iming.eu.org/2025/01/14/dailyhotapi-rss/</id>
    <link href="https://iming.eu.org/2025/01/14/dailyhotapi-rss/"/>
    <published>2025-01-14T02:00:00.000Z</published>
    <summary>原项目已经提供了一些订阅接口，但是无法涵盖每个人的实际使用情况，所以简单介绍一下如何自定义自己需要的订阅接口。</summary>
    <title>DailyHotAPI 自定义 RSS 订阅接口</title>
    <updated>2025-01-17T03:41:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="VPS" scheme="https://iming.eu.org/categories/VPS/"/>
    <category term="Hysteria2" scheme="https://iming.eu.org/tags/Hysteria2/"/>
    <category term="端口跳跃" scheme="https://iming.eu.org/tags/%E7%AB%AF%E5%8F%A3%E8%B7%B3%E8%B7%83/"/>
    <category term="iptables" scheme="https://iming.eu.org/tags/iptables/"/>
    <content>
      <![CDATA[<h2 id="服务端配置"><a href="#服务端配置" class="headerlink" title="服务端配置"></a>服务端配置</h2><h3 id="安装-iptables-persistent"><a href="#安装-iptables-persistent" class="headerlink" title="安装 iptables-persistent"></a>安装 iptables-persistent</h3><p><code>iptables-persistent</code> 用于保存和恢复 <code>iptables</code> 规则。默认情况下，<code>iptables</code> 规则在系统重启后会丢失。安装 <code>iptables-persistent</code> 可以确保这些规则在系统重启后自动加载，从而实现规则的持久化。</p><p>打开终端并运行以下命令来安装 <code>iptables-persistent</code>：</p><figure class="highlight shell"><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 prompt_">#</span><span class="language-bash">安装 iptables-persistent</span></span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install iptables-persistent</span><br></pre></td></tr></table></figure><p>在安装过程中，系统会提示你是否要保存当前的 <code>iptables</code> 规则，选择”Yes”。</p><h3 id="添加-iptables-规则"><a href="#添加-iptables-规则" class="headerlink" title="添加 iptables 规则"></a>添加 iptables 规则</h3><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">将20000:50000的端口转发到Hy2端口10086</span></span><br><span class="line">sudo iptables -t nat -A PREROUTING -i eth0 -p udp --dport 20000:50000 -j REDIRECT --to-ports 10086</span><br></pre></td></tr></table></figure><h3 id="保存当前的-iptables-规则"><a href="#保存当前的-iptables-规则" class="headerlink" title="保存当前的 iptables 规则"></a>保存当前的 iptables 规则</h3><p>安装完成后，你可以使用以下命令手动保存当前的 <code>iptables</code> 规则：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo netfilter-persistent save</span><br></pre></td></tr></table></figure><h3 id="验证规则是否持久化"><a href="#验证规则是否持久化" class="headerlink" title="验证规则是否持久化"></a>验证规则是否持久化</h3><p>重新启动系统或重启 <code>netfilter-persistent</code> 服务以确保规则持久化：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl restart netfilter-persistent</span><br></pre></td></tr></table></figure><p>你可以使用以下命令来查看当前的 <code>iptables</code> 规则，确保它们已正确保存：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo iptables -t nat -L -v</span><br></pre></td></tr></table></figure><h3 id="重启-Hy2-服务"><a href="#重启-Hy2-服务" class="headerlink" title="重启 Hy2 服务"></a>重启 Hy2 服务</h3><p>运行以下命令重启 Hy2 服务：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl restart hysteria-server.service</span><br></pre></td></tr></table></figure><h3 id="查看-Hy2-运行状态"><a href="#查看-Hy2-运行状态" class="headerlink" title="查看 Hy2 运行状态"></a>查看 Hy2 运行状态</h3><p>运行以下命令查看 Hy2 服务的运行状态：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl status hysteria-server.service</span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装 iptables-persistent</span></span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install iptables-persistent</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加 iptables 规则</span></span><br><span class="line">sudo iptables -t nat -A PREROUTING -i eth0 -p udp --dport 20000:50000 -j REDIRECT --to-ports 10086</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">保存当前的 iptables 规则</span></span><br><span class="line">sudo netfilter-persistent save</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证规则是否持久化</span></span><br><span class="line">sudo systemctl restart netfilter-persistent</span><br><span class="line">sudo iptables -t nat -L -v</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启Hy2服务</span></span><br><span class="line">systemctl restart hysteria-server.service</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看Hy2运行状态</span></span><br><span class="line">systemctl status hysteria-server.service</span><br></pre></td></tr></table></figure><h2 id="客户端配置"><a href="#客户端配置" class="headerlink" title="客户端配置"></a>客户端配置</h2><h3 id="v2rayN"><a href="#v2rayN" class="headerlink" title="v2rayN"></a>v2rayN</h3><ul><li><p>点击 <code>服务器</code> -&gt; <code>添加自定义配置服务器</code></p></li><li><p>随意设置 <code>别名</code></p></li><li><p><code>地址</code> -&gt; <code>浏览</code> -&gt; 选择 <code>xxx.json</code> &#x2F; <code>xxx.txt</code>（你自己的配置文件）</p><figure class="highlight json"><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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;server&quot;</span><span class="punctuation">:</span> <span class="string">&quot;13.1.1.1:10086,20000-50000&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;auth&quot;</span><span class="punctuation">:</span> <span class="string">&quot;password&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;bandwidth&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;up&quot;</span><span class="punctuation">:</span> <span class="string">&quot;50 mbps&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;down&quot;</span><span class="punctuation">:</span> <span class="string">&quot;100 mbps&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;transport&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;udp&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;udp&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;hopInterval&quot;</span><span class="punctuation">:</span> <span class="string">&quot;30s&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;tls&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;sni&quot;</span><span class="punctuation">:</span> <span class="string">&quot;vercel.com&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;insecure&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;socks5&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;listen&quot;</span><span class="punctuation">:</span> <span class="string">&quot;127.0.0.1:1080&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;http&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;listen&quot;</span><span class="punctuation">:</span> <span class="string">&quot;127.0.0.1:8080&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></li><li><p><code>Core 类型</code> 选择 <code>hysteria2</code></p></li><li><p><code>Socks 端口</code> 输入地址配置文件中的端口 <code>1080</code></p></li><li><p>点击确定保存使用（可配合 Tun 模式使用）</p></li></ul><h3 id="v2rayNG"><a href="#v2rayNG" class="headerlink" title="v2rayNG"></a>v2rayNG</h3><p>订阅格式：</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hysteria2://password@13.1.1.1:10086?<span class="attr">security</span>=tls&amp;insecure=<span class="number">1</span>&amp;mport=<span class="number">20000</span>-<span class="number">50000</span>&amp;sni=vercel.com<span class="comment">#Hy2-JP</span></span><br></pre></td></tr></table></figure><blockquote><p><a href="https://v2.hysteria.network/zh/docs/advanced/Port-Hopping">参阅文档</a></p></blockquote>]]>
    </content>
    <id>https://iming.eu.org/2024/12/30/hysteria2-port-hopping/</id>
    <link href="https://iming.eu.org/2024/12/30/hysteria2-port-hopping/"/>
    <published>2024-12-30T09:00:00.000Z</published>
    <summary>用于防止 QoS 阻断或限速 UDP 连接。</summary>
    <title>Hysteria 2 端口跳跃</title>
    <updated>2026-05-18T03:22:11.259Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="游戏" scheme="https://iming.eu.org/categories/%E6%B8%B8%E6%88%8F/"/>
    <category term="黑神话悟空" scheme="https://iming.eu.org/tags/%E9%BB%91%E7%A5%9E%E8%AF%9D%E6%82%9F%E7%A9%BA/"/>
    <category term="壁纸" scheme="https://iming.eu.org/tags/%E5%A3%81%E7%BA%B8/"/>
    <content>
      <![CDATA[<h2 id="第一回-《火照黑云》"><a href="#第一回-《火照黑云》" class="headerlink" title="第一回 《火照黑云》"></a>第一回 《火照黑云》</h2><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/SixRoots-01-ISee.large.webp" data-pswp-width="1920" data-pswp-height="1080" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/SixRoots-01-ISee.thumb.webp" width="1280" height="720" alt="看见" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/Mural-01.large.webp" data-pswp-width="2400" data-pswp-height="1350" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/Mural-01.thumb.webp" width="1280" height="720" alt="火照黑云" loading="lazy" decoding="async"></a></p><iframe style="border-radius:12px" src="https://spotify.jianbing.tk/embed/track/3ejpojtizqlony9KMqEgld?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe><h2 id="第二回-《风起黄昏》"><a href="#第二回-《风起黄昏》" class="headerlink" title="第二回 《风起黄昏》"></a>第二回 《风起黄昏》</h2><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/SixRoots-02-DeafEar.large.webp" data-pswp-width="1920" data-pswp-height="1080" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/SixRoots-02-DeafEar.thumb.webp" width="1280" height="720" alt="聋" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/Mural-02.large.webp" data-pswp-width="2400" data-pswp-height="1350" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/Mural-02.thumb.webp" width="1280" height="720" alt="风起黄昏" loading="lazy" decoding="async"></a></p><iframe style="border-radius:12px" src="https://spotify.jianbing.tk/embed/track/5KHnY1pSIDvbPgeAexESts?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe><h2 id="第三回-《夜生白露》"><a href="#第三回-《夜生白露》" class="headerlink" title="第三回 《夜生白露》"></a>第三回 《夜生白露》</h2><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/SixRoots-03-Nosense.large.webp" data-pswp-width="1920" data-pswp-height="1080" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/SixRoots-03-Nosense.thumb.webp" width="1280" height="720" alt="屁" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/Mural-03.large.webp" data-pswp-width="2400" data-pswp-height="1350" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/Mural-03.thumb.webp" width="1280" height="720" alt="夜生白露" loading="lazy" decoding="async"></a></p><iframe style="border-radius:12px" src="https://spotify.jianbing.tk/embed/track/3wH3dMU58oJetYo5UvY424?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe><h2 id="第四回-《曲度紫鸳》"><a href="#第四回-《曲度紫鸳》" class="headerlink" title="第四回 《曲度紫鸳》"></a>第四回 《曲度紫鸳》</h2><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/SixRoots-04-ListenNot.large.webp" data-pswp-width="1920" data-pswp-height="1080" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/SixRoots-04-ListenNot.thumb.webp" width="1280" height="720" alt="勿听" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/Mural-04.large.webp" data-pswp-width="2400" data-pswp-height="1350" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/Mural-04.thumb.webp" width="1280" height="720" alt="曲度紫鸳" loading="lazy" decoding="async"></a></p><iframe style="border-radius:12px" src="https://spotify.jianbing.tk/embed/track/1qzckNoWUywnkdYYklWmTs?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe><h2 id="第五回-《日落红尘》"><a href="#第五回-《日落红尘》" class="headerlink" title="第五回 《日落红尘》"></a>第五回 《日落红尘》</h2><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/SixRoots-05-Destiny.large.webp" data-pswp-width="1920" data-pswp-height="1080" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/SixRoots-05-Destiny.thumb.webp" width="1280" height="720" alt="不由己" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/Mural-05.large.webp" data-pswp-width="2400" data-pswp-height="1350" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/Mural-05.thumb.webp" width="1280" height="720" alt="日落红尘" loading="lazy" decoding="async"></a></p><iframe style="border-radius:12px" src="https://spotify.jianbing.tk/embed/track/2ssnCoeFqhte8ZI6XIj4D9?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe><h2 id="第六回-《未竟》"><a href="#第六回-《未竟》" class="headerlink" title="第六回 《未竟》"></a>第六回 《未竟》</h2><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/SixRoots-06-Unfinished.large.webp" data-pswp-width="1920" data-pswp-height="1080" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/SixRoots-06-Unfinished.thumb.webp" width="1280" height="720" alt="未尽" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/Mural-06.large.webp" data-pswp-width="2400" data-pswp-height="1350" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/Mural-06.thumb.webp" width="1280" height="720" alt="未竟" loading="lazy" decoding="async"></a></p><iframe style="border-radius:12px" src="https://spotify.jianbing.tk/embed/track/6wSh7DtQRJeknT6MCsuMfu?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe><h2 id="隐藏梅山"><a href="#隐藏梅山" class="headerlink" title="隐藏梅山"></a>隐藏梅山</h2><p><a class="pswp-link" href="/2024/12/11/black-myth-wukong-murals/Mural-Meishan.large.webp" data-pswp-width="2400" data-pswp-height="1350" target="_blank" rel="noopener"><img src="/2024/12/11/black-myth-wukong-murals/Mural-Meishan.thumb.webp" width="1280" height="720" alt="隐藏梅山" loading="lazy" decoding="async"></a></p>]]>
    </content>
    <id>https://iming.eu.org/2024/12/11/black-myth-wukong-murals/</id>
    <link href="https://iming.eu.org/2024/12/11/black-myth-wukong-murals/"/>
    <published>2024-12-11T06:44:00.000Z</published>
    <summary>温馨提示：由于图片分辨率较高，文件大小也相应较大，加载可能需要一些时间，请耐心等待。</summary>
    <title>黑神话：悟空 - 全章节8K壁画</title>
    <updated>2026-05-18T03:22:10.735Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="脚本" scheme="https://iming.eu.org/categories/%E8%84%9A%E6%9C%AC/"/>
    <category term="UPX" scheme="https://iming.eu.org/tags/UPX/"/>
    <category term="批处理" scheme="https://iming.eu.org/tags/%E6%89%B9%E5%A4%84%E7%90%86/"/>
    <category term="压缩" scheme="https://iming.eu.org/tags/%E5%8E%8B%E7%BC%A9/"/>
    <category term="Windows" scheme="https://iming.eu.org/tags/Windows/"/>
    <content>
      <![CDATA[<h2 id="使用-UPX-批量压缩程序的批处理脚本"><a href="#使用-UPX-批量压缩程序的批处理脚本" class="headerlink" title="使用 UPX 批量压缩程序的批处理脚本"></a>使用 UPX 批量压缩程序的批处理脚本</h2><p>在软件开发和发布过程中，程序的体积往往是一个需要考虑的重要因素。<a href="https://github.com/upx/upx">UPX（Ultimate Packer for eXecutables）</a> 是一个强大的可执行文件压缩工具，可以有效减小程序的体积。本文将介绍一个简单的批处理脚本，帮助用户在 Windows 环境下批量压缩同一文件夹中的所有 <code>.exe</code> 文件。</p><h2 id="脚本功能"><a href="#脚本功能" class="headerlink" title="脚本功能"></a>脚本功能</h2><p>该脚本提供了多种压缩模式供用户选择，包括：</p><ul><li><strong>最高压缩比 (-9)</strong>：适合对文件大小要求严格的情况。</li><li><strong>快速压缩 (-1)</strong>：适合对压缩速度有要求的情况。</li><li><strong>最佳压缩 (–best)</strong>：可能会更慢，但通常能得到更小的文件。</li><li><strong>还原压缩 (–decompress)</strong>：恢复到未压缩状态。</li><li><strong>默认压缩</strong>：不指定任何参数以使用 UPX 的默认设置。</li></ul><p>用户可以通过简单的菜单选择所需的压缩模式。</p><h2 id="脚本代码"><a href="#脚本代码" class="headerlink" title="脚本代码"></a>脚本代码</h2><p>以下是完整的批处理脚本代码：</p><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line">@ECHO OFF</span><br><span class="line">CHCP 65001</span><br><span class="line">SET UPX_PATH=D:\upx\upx-4.0.2-win64\upx.exe</span><br><span class="line"></span><br><span class="line">:MENU</span><br><span class="line">ECHO.</span><br><span class="line">ECHO ===========================</span><br><span class="line">ECHO      UPX 批量程序打包</span><br><span class="line">ECHO ===========================</span><br><span class="line">ECHO 1. 最高压缩比 (-9)</span><br><span class="line">ECHO 2. 快速压缩 (-1)</span><br><span class="line">ECHO 3. 最佳压缩 (--best)</span><br><span class="line">ECHO 4. 还原压缩 (--decompress)</span><br><span class="line">ECHO 5. 默认压缩 (不指定参数)</span><br><span class="line">ECHO 6. 显示帮助</span><br><span class="line">ECHO 7. 退出</span><br><span class="line">ECHO ===========================</span><br><span class="line">SET /P CHOICE=<span class="string">&quot;请选择一个选项 (1-7) [默认选择5]: &quot;</span></span><br><span class="line"></span><br><span class="line">IF <span class="string">&quot;%CHOICE%&quot;</span>==<span class="string">&quot;&quot;</span> SET CHOICE=5  :: 如果没有输入，默认选择5</span><br><span class="line">IF <span class="string">&quot;%CHOICE%&quot;</span>==<span class="string">&quot;1&quot;</span> SET COMPRESS_MODE=-9</span><br><span class="line">IF <span class="string">&quot;%CHOICE%&quot;</span>==<span class="string">&quot;2&quot;</span> SET COMPRESS_MODE=-1</span><br><span class="line">IF <span class="string">&quot;%CHOICE%&quot;</span>==<span class="string">&quot;3&quot;</span> SET COMPRESS_MODE=--best</span><br><span class="line">IF <span class="string">&quot;%CHOICE%&quot;</span>==<span class="string">&quot;4&quot;</span> SET COMPRESS_MODE=--decompress</span><br><span class="line">IF <span class="string">&quot;%CHOICE%&quot;</span>==<span class="string">&quot;5&quot;</span> SET COMPRESS_MODE=   :: 不设置任何参数以使用默认压缩</span><br><span class="line">IF <span class="string">&quot;%CHOICE%&quot;</span>==<span class="string">&quot;6&quot;</span> GOTO HELP</span><br><span class="line">IF <span class="string">&quot;%CHOICE%&quot;</span>==<span class="string">&quot;7&quot;</span> EXIT</span><br><span class="line"></span><br><span class="line">IF NOT DEFINED COMPRESS_MODE (</span><br><span class="line">    ECHO 无效选择，请重新运行脚本并选择有效选项。</span><br><span class="line">    PAUSE</span><br><span class="line">    GOTO MENU</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">REM 检查目录中的 .exe 文件并进行操作</span><br><span class="line">FOR %%F IN (%~dp0*.exe) DO (</span><br><span class="line">    ECHO 操作文件: %%F 使用模式: %COMPRESS_MODE%</span><br><span class="line">    IF DEFINED COMPRESS_MODE (</span><br><span class="line">        <span class="string">&quot;%UPX_PATH%&quot;</span> %COMPRESS_MODE% <span class="string">&quot;%%F&quot;</span></span><br><span class="line">    ) ELSE (</span><br><span class="line">        <span class="string">&quot;%UPX_PATH%&quot;</span> <span class="string">&quot;%%F&quot;</span>  :: 使用默认方式进行压缩</span><br><span class="line">    )</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">ECHO.</span><br><span class="line">ECHO Done!</span><br><span class="line">ECHO 该目录下所有的 .exe 文件已经被处理。</span><br><span class="line">PAUSE</span><br><span class="line"></span><br><span class="line">GOTO MENU  :: 返回菜单</span><br><span class="line"></span><br><span class="line">:HELP</span><br><span class="line">ECHO.</span><br><span class="line">ECHO UPX 工具帮助信息:</span><br><span class="line">ECHO ===========================</span><br><span class="line">ECHO -9      : 最高压缩比，适合对文件大小要求严格的情况</span><br><span class="line">ECHO -1      : 快速压缩，适合对压缩速度有要求的情况</span><br><span class="line">ECHO --best  : 最佳压缩，可能会更慢，但通常能得到更小的文件</span><br><span class="line">ECHO --decompress : 还原压缩，恢复到未压缩状态</span><br><span class="line">ECHO ===========================</span><br><span class="line">PAUSE</span><br><span class="line">GOTO MENU</span><br></pre></td></tr></table></figure><h2 id="使用说明"><a href="#使用说明" class="headerlink" title="使用说明"></a>使用说明</h2><ol><li>将上述代码复制并粘贴到一个新的文本文件中，保存为 <code>upx_batch.bat</code>。</li><li>确保将 <code>UPX_PATH</code> 设置为 UPX 可执行文件的正确路径。</li><li>双击运行 <code>upx_batch.bat</code> 文件。</li><li>按照屏幕上的提示选择所需的操作模式。</li></ol><p><a class="pswp-link" href="/2024/12/10/upx-batch-compression/upx-packbat.large.webp" data-pswp-width="1129" data-pswp-height="635" target="_blank" rel="noopener"><img src="/2024/12/10/upx-batch-compression/upx-packbat.thumb.webp" width="1129" height="635" alt="执行界面" loading="lazy" decoding="async"></a></p><h2 id="参考命令"><a href="#参考命令" class="headerlink" title="参考命令"></a>参考命令</h2><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line">默认压缩[upx 程序名.exe]</span><br><span class="line">较快压缩[upx -1 程序名.exe]</span><br><span class="line">较好压缩[upx -9 程序名.exe]</span><br><span class="line">最优压缩[upx --best 程序名.exe]</span><br><span class="line">还原压缩[upx -d 程序名.exe]</span><br><span class="line">测试是否是UPX压缩[upx -t 程序名.exe]</span><br><span class="line">显示UPX压缩清单[upx -l 程序名.exe]</span><br><span class="line">显示UPX版本[upx -V]</span><br><span class="line">显示UPX使用说明[upx -L]</span><br><span class="line">UPX使用帮助[upx -h]</span><br><span class="line">减少UPX压缩显示[upx -q 程序名.exe]</span><br><span class="line">增加UPX压缩显示[upx -v 程序名.exe]</span><br><span class="line">将UPX压缩另存为其它文件[upx -o 1.exe 程序名.exe]</span><br><span class="line">强制压缩可疑文件[upx -f 程序名.exe]</span><br><span class="line">保留备份文件[upx -k 程序名.exe]</span><br><span class="line">不备份UPX压缩[upx --no-backup 程序名.exe]</span><br><span class="line">无颜色UPX压缩[upx --no-color 程序名.exe]</span><br><span class="line">UPX压缩无进度条显示[upx --no-progress 程序名.exe]</span><br><span class="line">尝试所有可用的压缩方法和过滤器[慢][upx --brute 程序名.exe]</span><br><span class="line">超级暴力尝试更多的压缩变体[非常慢] [upx --ultra-brute 程序名.exe]</span><br><span class="line">保留额外数据[默认值][upx --overlay=copy 程序名.exe]</span><br><span class="line">覆盖额外数据[upx --overlay=strip 程序名.exe]</span><br><span class="line">不处理额外数据[upx --overlay=skip 程序名.exe]</span><br><span class="line">压缩导出部分[upx --compress-exports=1 程序名.exe]</span><br><span class="line">不压缩导出部分[upx --compress-exports=0 程序名.exe]</span><br><span class="line">压缩所有图标[upx --compress-icons=3 程序名.exe]</span><br><span class="line">压缩除第一个图标以外的所有图标[upx --compress-icons=1 程序名.exe]</span><br><span class="line">压缩除第一个图标目录外的所有图标[默认值][upx --compress-icons=2 程序名.exe]</span><br><span class="line">不压缩任何图标[upx --compress-icons=0 程序名.exe]</span><br><span class="line">不压缩任何资源[upx --compress-resources=0 程序名.exe]</span><br><span class="line">不压缩list指定的资源[upx --keep-resource=list 程序名.exe]</span><br><span class="line">不剥离重定位[upx --strip-relocs=0 程序名.exe]</span><br><span class="line">剥离重定位[upx --strip-relocs=1 程序名.exe]</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过这个简单的批处理脚本，便于批量压缩同一文件夹中的所有 <code>.exe</code> 文件，同时可借助 UPX 参考命令来定制不同的压缩模式。</p>]]>
    </content>
    <id>https://iming.eu.org/2024/12/10/upx-batch-compression/</id>
    <link href="https://iming.eu.org/2024/12/10/upx-batch-compression/"/>
    <published>2024-12-10T02:11:00.000Z</published>
    <summary>一个简单的批处理脚本，用于在 Windows 环境下批量压缩同一文件夹中的所有 .exe 文件。</summary>
    <title>使用 UPX 批量压缩程序的批处理脚本</title>
    <updated>2026-05-18T03:22:11.271Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="Qt" scheme="https://iming.eu.org/categories/Qt/"/>
    <category term="Xlsx" scheme="https://iming.eu.org/tags/Xlsx/"/>
    <category term="QXlsx" scheme="https://iming.eu.org/tags/QXlsx/"/>
    <category term="Chart" scheme="https://iming.eu.org/tags/Chart/"/>
    <content>
      <![CDATA[<p>为了添加设置图例标题的功能，我们需要在 <code>Chart</code> 类中添加一个新的方法，并在 <code>ChartPrivate</code> 类中实现相应的功能。以下是修改后的代码：</p><ol><li><p>在 <code>xlsxchart.h</code> 文件中，在 <code>Chart</code> 类的公共方法部分添加以下声明：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// xlsxchart.h</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// ... (前面的代码保持不变)</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">addSeries</span><span class="params">(<span class="type">const</span> CellRange &amp;range,</span></span></span><br><span class="line"><span class="params"><span class="function">                   AbstractSheet *sheet = <span class="literal">nullptr</span>,</span></span></span><br><span class="line"><span class="params"><span class="function">                   <span class="type">bool</span> headerH         = <span class="literal">false</span>,</span></span></span><br><span class="line"><span class="params"><span class="function">                   <span class="type">bool</span> headerV         = <span class="literal">false</span>,</span></span></span><br><span class="line"><span class="params"><span class="function">                   <span class="type">bool</span> swapHeaders     = <span class="literal">false</span>)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">setChartType</span><span class="params">(ChartType type)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">setChartStyle</span><span class="params">(<span class="type">int</span> id)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">setAxisTitle</span><span class="params">(Chart::ChartAxisPos pos, QString axisTitle)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">setChartTitle</span><span class="params">(QString strchartTitle)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">setChartLegend</span><span class="params">(Chart::ChartAxisPos legendPos, <span class="type">bool</span> overlap = <span class="literal">false</span>)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">setGridlinesEnable</span><span class="params">(<span class="type">bool</span> majorGridlinesEnable = <span class="literal">false</span>, <span class="type">bool</span> minorGridlinesEnable = <span class="literal">false</span>)</span></span>;</span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">setSeriesName</span><span class="params">(<span class="type">int</span> index, <span class="type">const</span> QString &amp;name)</span></span>; <span class="comment">// 新添加的方法</span></span><br><span class="line"><span class="comment">// ... (后面的代码保持不变)</span></span><br></pre></td></tr></table></figure></li><li><p>在 <code>xlsxchart_p.h</code> 文件中，在 <code>ChartPrivate</code> 类中添加以下成员：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// xlsxchart_P.h</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// ... (前面的代码保持不变)</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    Chart::ChartType chartType;</span><br><span class="line">    QList&lt;std::shared_ptr&lt;XlsxSeries&gt;&gt; seriesList;</span><br><span class="line">    QList&lt;std::shared_ptr&lt;XlsxAxis&gt;&gt; axisList;</span><br><span class="line">    QMap&lt;XlsxAxis::AxisPos, QString&gt; axisNames;</span><br><span class="line">    QString chartTitle;</span><br><span class="line">    AbstractSheet *sheet;</span><br><span class="line">    Chart::ChartAxisPos legendPos;</span><br><span class="line">    <span class="type">bool</span> legendOverlay;</span><br><span class="line">    <span class="type">bool</span> majorGridlinesEnabled;</span><br><span class="line">    <span class="type">bool</span> minorGridlinesEnabled;</span><br><span class="line"></span><br><span class="line">    QString layout; <span class="comment">// only for storing a read file</span></span><br><span class="line"></span><br><span class="line">    QMap&lt;<span class="type">int</span>, QString&gt; seriesNames; <span class="comment">// 新添加</span></span><br><span class="line"><span class="comment">// ... (后面的代码保持不变)</span></span><br></pre></td></tr></table></figure></li><li><p>在 <code>xlsxchart.cpp</code> 文件中，添加以下方法实现：</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">Chart::setSeriesName</span><span class="params">(<span class="type">int</span> index, <span class="type">const</span> QString &amp;name)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">Q_D</span>(Chart);</span><br><span class="line">    d-&gt;seriesNames[index] = name;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>在 <code>ChartPrivate::saveXmlSer</code> 方法中，修改保存系列名称的部分。在 <code>writer.writeStartElement(QStringLiteral(&quot;c:ser&quot;));</code> 之后添加以下代码：</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">ChartPrivate::saveXmlSer</span><span class="params">(QXmlStreamWriter &amp;writer, XlsxSeries *ser, <span class="type">int</span> id)</span> <span class="type">const</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    writer.<span class="built_in">writeStartElement</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;c:ser&quot;</span>));</span><br><span class="line">    writer.<span class="built_in">writeEmptyElement</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;c:idx&quot;</span>));</span><br><span class="line">    writer.<span class="built_in">writeAttribute</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;val&quot;</span>), QString::<span class="built_in">number</span>(id));</span><br><span class="line">    writer.<span class="built_in">writeEmptyElement</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;c:order&quot;</span>));</span><br><span class="line">    writer.<span class="built_in">writeAttribute</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;val&quot;</span>), QString::<span class="built_in">number</span>(id));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加自定义系列名称</span></span><br><span class="line">    <span class="keyword">if</span> (seriesNames.<span class="built_in">contains</span>(id)) &#123;</span><br><span class="line">        writer.<span class="built_in">writeStartElement</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;c:tx&quot;</span>));</span><br><span class="line">        writer.<span class="built_in">writeStartElement</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;c:v&quot;</span>));</span><br><span class="line">        writer.<span class="built_in">writeCharacters</span>(seriesNames[id]);</span><br><span class="line">        writer.<span class="built_in">writeEndElement</span>(); <span class="comment">// c:v</span></span><br><span class="line">        writer.<span class="built_in">writeEndElement</span>(); <span class="comment">// c:tx</span></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!ser-&gt;headerV_numRef.<span class="built_in">isEmpty</span>()) &#123;</span><br><span class="line">        writer.<span class="built_in">writeStartElement</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;c:tx&quot;</span>));</span><br><span class="line">        writer.<span class="built_in">writeStartElement</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;c:strRef&quot;</span>));</span><br><span class="line">        writer.<span class="built_in">writeTextElement</span>(<span class="built_in">QStringLiteral</span>(<span class="string">&quot;c:f&quot;</span>), ser-&gt;headerV_numRef);</span><br><span class="line">        writer.<span class="built_in">writeEndElement</span>(); <span class="comment">// c:strRef</span></span><br><span class="line">        writer.<span class="built_in">writeEndElement</span>(); <span class="comment">// c:tx</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ... (其余代码保持不变)</span></span><br><span class="line"></span><br><span class="line">    writer.<span class="built_in">writeEndElement</span>(); <span class="comment">// c:ser</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol><p>然后，你可以根据需要设置系列名称为对应的列标题：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加数据系列</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> col = <span class="number">2</span>; col &lt; headers.<span class="built_in">size</span>(); ++col) &#123;</span><br><span class="line">    <span class="function">QXlsx::CellRange <span class="title">range</span><span class="params">(<span class="number">3</span>, col + <span class="number">1</span>, row - <span class="number">1</span>, col + <span class="number">1</span>)</span></span>;</span><br><span class="line">    lineChart-&gt;<span class="built_in">addSeries</span>(range, xlsx.<span class="built_in">currentSheet</span>(), <span class="literal">true</span>, <span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 设置系列名称为对应的列标题</span></span><br><span class="line">    lineChart-&gt;<span class="built_in">setSeriesName</span>(col - <span class="number">2</span>, headers[col]);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>原始 QXlsx 插入折线图：</p><p><img loading="lazy" decoding="async" src="https://pic.jianbing.tk/imgs/image-20241010162436162.png" alt="image-20241010162436162"></p><p>自定义导出标题后：</p><p><img loading="lazy" decoding="async" src="https://pic.jianbing.tk/imgs/image-20241010162521454.png" alt="image-20241010162521454"></p>]]>
    </content>
    <id>https://iming.eu.org/2024/10/10/qt-xlsx-chart/</id>
    <link href="https://iming.eu.org/2024/10/10/qt-xlsx-chart/"/>
    <published>2024-10-10T08:35:00.000Z</published>
    <summary>扩展 QXlsx 库以支持自定义 Excel 图表中的系列名称。</summary>
    <title>自定义 Excel 图表系列名称——QXlsx 库的扩展实现</title>
    <updated>2026-05-18T03:22:11.263Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="Qt" scheme="https://iming.eu.org/categories/Qt/"/>
    <category term="Word" scheme="https://iming.eu.org/tags/Word/"/>
    <category term="QAxObject" scheme="https://iming.eu.org/tags/QAxObject/"/>
    <content>
      <![CDATA[<h2 id="使用-QAxObject-进行-Word-文档生成：基于子线程的导出任务"><a href="#使用-QAxObject-进行-Word-文档生成：基于子线程的导出任务" class="headerlink" title="使用 QAxObject 进行 Word 文档生成：基于子线程的导出任务"></a>使用 QAxObject 进行 Word 文档生成：基于子线程的导出任务</h2><p>在使用 Qt 开发应用时，有时需要生成 Word 文档。在这篇文章中，我们将讨论如何通过子线程使用 <code>QAxObject</code> 生成 Word 文档。以下代码演示了如何在子线程中处理文档导出任务。</p><h3 id="成品演示"><a href="#成品演示" class="headerlink" title="成品演示"></a>成品演示</h3><p><a class="pswp-link" href="/2024/06/12/qt-export-word/uiDemo.large.webp" data-pswp-width="943" data-pswp-height="724" target="_blank" rel="noopener"><img src="/2024/06/12/qt-export-word/uiDemo.thumb.webp" width="943" height="724" alt="软件Demo" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/06/12/qt-export-word/exportWordDemo.large.webp" data-pswp-width="564" data-pswp-height="713" target="_blank" rel="noopener"><img src="/2024/06/12/qt-export-word/exportWordDemo.thumb.webp" width="564" height="713" alt="导出报告Demo" loading="lazy" decoding="async"></a></p><h3 id="代码结构"><a href="#代码结构" class="headerlink" title="代码结构"></a>代码结构</h3><p>首先，我们有一个 <code>ExportTask</code> 类，继承自 <code>QObject</code>，并且包含了以下功能：</p><ul><li>初始化：将 <code>QVariantMap</code> 数据作为参数传递给构造函数。</li><li>文档处理：在 <code>process()</code> 函数中创建和编辑 Word 文档。</li><li>书签替换：<code>replaceBookmarkText()</code> 函数用于替换文档中的书签文本。</li><li>表格行添加：<code>addRowToTable()</code> 函数用于在指定的表格中添加行。</li><li>合并单元格：<code>MergeCells()</code> 函数用于合并表格中的单元格。</li><li>合并相同值单元格：<code>mergeSameRefResCells()</code> 函数用于合并相同值的单元格。</li></ul><h2 id="关键部分分析"><a href="#关键部分分析" class="headerlink" title="关键部分分析"></a>关键部分分析</h2><h3 id="构造函数与-QVariantMap-数据"><a href="#构造函数与-QVariantMap-数据" class="headerlink" title="构造函数与 QVariantMap 数据"></a>构造函数与 <code>QVariantMap</code> 数据</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ExportTask::<span class="built_in">ExportTask</span>(<span class="type">const</span> QVariantMap&amp; data) : <span class="built_in">data</span>(data) &#123;&#125;</span><br></pre></td></tr></table></figure><p>这个构造函数接受一个 <code>QVariantMap</code>，它包含了所需的所有数据。确保传递的 <code>QVariantMap</code> 包含所有必要的键和值。</p><h3 id="process-函数：文档处理的核心"><a href="#process-函数：文档处理的核心" class="headerlink" title="process() 函数：文档处理的核心"></a><code>process()</code> 函数：文档处理的核心</h3><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><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">ExportTask::process</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="built_in">CoInitialize</span>(<span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line">    QAxObject* word = <span class="keyword">new</span> <span class="built_in">QAxObject</span>(<span class="string">&quot;Word.Application&quot;</span>);</span><br><span class="line">    word-&gt;<span class="built_in">setProperty</span>(<span class="string">&quot;Visible&quot;</span>, <span class="literal">false</span>);</span><br><span class="line">    QAxObject *documents = word-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Documents&quot;</span>);</span><br><span class="line">    documents-&gt;<span class="built_in">dynamicCall</span>(<span class="string">&quot;Add(QString)&quot;</span>, data[<span class="string">&quot;templatePath&quot;</span>].<span class="built_in">toString</span>());</span><br><span class="line">    QAxObject *document = word-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;ActiveDocument&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 替换书签文本</span></span><br><span class="line">    <span class="built_in">replaceBookmarkText</span>(document, <span class="string">&quot;lineEdit1&quot;</span>, data[<span class="string">&quot;lineEdit1&quot;</span>].<span class="built_in">toString</span>());</span><br><span class="line">    <span class="built_in">replaceBookmarkText</span>(document, <span class="string">&quot;reportNum&quot;</span>, data[<span class="string">&quot;reportNum&quot;</span>].<span class="built_in">toString</span>());</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加表格行</span></span><br><span class="line">    QAxObject* table = document-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Tables(int)&quot;</span>, <span class="number">2</span>);</span><br><span class="line">    QAxObject* rows = table-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Rows&quot;</span>);</span><br><span class="line"></span><br><span class="line">    foreach (<span class="type">const</span> QVariant&amp; row, data[<span class="string">&quot;tableRows&quot;</span>].<span class="built_in">toList</span>()) &#123;</span><br><span class="line">        <span class="built_in">addRowToTable</span>(rows, row.<span class="built_in">toMap</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 清理对象</span></span><br><span class="line">    <span class="keyword">delete</span> rows;</span><br><span class="line">    <span class="keyword">delete</span> table;</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><br><span class="line">    <span class="comment">// 合并相同值的单元格</span></span><br><span class="line">    <span class="built_in">mergeSameRefResCells</span>(newTable, data[<span class="string">&quot;measurements&quot;</span>].<span class="built_in">toList</span>());</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 保存文档</span></span><br><span class="line">    QString tempPath = QDir::<span class="built_in">tempPath</span>() + <span class="string">&quot;/TempDoc_&quot;</span> + timestamp + <span class="string">&quot;.docx&quot;</span>;</span><br><span class="line">    document-&gt;<span class="built_in">dynamicCall</span>(<span class="string">&quot;SaveAs(const QString&amp;)&quot;</span>, QDir::<span class="built_in">toNativeSeparators</span>(tempPath));</span><br><span class="line">    document-&gt;<span class="built_in">dynamicCall</span>(<span class="string">&quot;Close (boolean)&quot;</span>, <span class="literal">false</span>);</span><br><span class="line">    word-&gt;<span class="built_in">dynamicCall</span>(<span class="string">&quot;Quit()&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function">emit <span class="title">finished</span><span class="params">(timestamp, tempPath)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">CoUninitialize</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意点：</p><ul><li><strong>CoInitialize</strong>：调用 <code>CoInitialize(NULL)</code> 进行 COM 初始化，并在最后调用 <code>CoUninitialize()</code> 进行清理。</li><li><strong>QAxObject</strong>：用于操控 Word 应用程序和文档。需要创建 Word 实例，加载模板文档，编辑文档内容，并最终保存文档。</li><li><strong>动态调用方法</strong>：使用 <code>dynamicCall</code> 动态调用 Word 方法，如 <code>Add</code>, <code>SaveAs</code>, <code>Close</code> 等。</li></ul><h3 id="replaceBookmarkText-函数：书签文本替换"><a href="#replaceBookmarkText-函数：书签文本替换" class="headerlink" title="replaceBookmarkText() 函数：书签文本替换"></a><code>replaceBookmarkText()</code> 函数：书签文本替换</h3><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">ExportTask::replaceBookmarkText</span><span class="params">(QAxObject* document, <span class="type">const</span> QString &amp;bookmarkName, <span class="type">const</span> QString &amp;text)</span> </span>&#123;</span><br><span class="line">    QAxObject *bookmark = document-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Bookmarks(QVariant)&quot;</span>, bookmarkName);</span><br><span class="line">    <span class="keyword">if</span> (!bookmark-&gt;<span class="built_in">isNull</span>()) &#123;</span><br><span class="line">        bookmark-&gt;<span class="built_in">dynamicCall</span>(<span class="string">&quot;Select(void)&quot;</span>);</span><br><span class="line">        QAxObject *range = bookmark-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Range&quot;</span>);</span><br><span class="line">        range-&gt;<span class="built_in">setProperty</span>(<span class="string">&quot;Text&quot;</span>, text);</span><br><span class="line">        <span class="comment">// 设置字体样式</span></span><br><span class="line">        QAxObject *font = range-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Font&quot;</span>);</span><br><span class="line">        font-&gt;<span class="built_in">setProperty</span>(<span class="string">&quot;Name&quot;</span>, <span class="string">&quot;宋体&quot;</span>);</span><br><span class="line">        font-&gt;<span class="built_in">setProperty</span>(<span class="string">&quot;Size&quot;</span>, <span class="number">9</span>);</span><br><span class="line">        font-&gt;<span class="built_in">setProperty</span>(<span class="string">&quot;Bold&quot;</span>, <span class="literal">false</span>);</span><br><span class="line">        <span class="keyword">delete</span> font;</span><br><span class="line">        <span class="keyword">delete</span> range;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">delete</span> bookmark;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意点：</p><ul><li><strong>检查书签是否存在</strong>：通过 <code>isNull</code> 检查书签是否存在。</li><li><strong>设置字体样式</strong>：可以自定义书签文本的字体和样式。</li></ul><h3 id="addRowToTable-函数：表格行添加"><a href="#addRowToTable-函数：表格行添加" class="headerlink" title="addRowToTable() 函数：表格行添加"></a><code>addRowToTable()</code> 函数：表格行添加</h3><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">ExportTask::addRowToTable</span><span class="params">(QAxObject* rows, <span class="type">const</span> QVariantMap&amp; rowData)</span> </span>&#123;</span><br><span class="line">    QAxObject* row = rows-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Add()&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (row) &#123;</span><br><span class="line">        QAxObject* cell1 = row-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Cells(int)&quot;</span>, <span class="number">1</span>);</span><br><span class="line">        <span class="keyword">if</span> (cell1) &#123;</span><br><span class="line">            cell1-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Range&quot;</span>)-&gt;<span class="built_in">setProperty</span>(<span class="string">&quot;Text&quot;</span>, rowData[<span class="string">&quot;checkBoxText&quot;</span>].<span class="built_in">toString</span>());</span><br><span class="line">            cell1-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Range&quot;</span>)-&gt;<span class="built_in">setProperty</span>(<span class="string">&quot;Style&quot;</span>, <span class="string">&quot;...&quot;</span>);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">delete</span> cell1;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">delete</span> row;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意点：</p><ul><li><strong>检查行和单元格是否存在</strong>：确保 <code>row</code> 对象存在再添加数据。</li><li><strong>设置单元格属性</strong>：可以为单元格设置文本和样式。</li></ul><h3 id="MergeCells-函数：单元格合并"><a href="#MergeCells-函数：单元格合并" class="headerlink" title="MergeCells() 函数：单元格合并"></a><code>MergeCells()</code> 函数：单元格合并</h3><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">ExportTask::MergeCells</span><span class="params">(QAxObject *table, <span class="type">int</span> nStartRow, <span class="type">int</span> nStartCol, <span class="type">int</span> nEndRow, <span class="type">int</span> nEndCol)</span> </span>&#123;</span><br><span class="line">    QAxObject* StartCell = table-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Cell(int, int)&quot;</span>, nStartRow, nStartCol);</span><br><span class="line">    QAxObject* EndCell = table-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Cell(int, int)&quot;</span>, nEndRow, nEndCol);</span><br><span class="line">    StartCell-&gt;<span class="built_in">dynamicCall</span>(<span class="string">&quot;Merge(LPDISPATCH)&quot;</span>, EndCell-&gt;<span class="built_in">asVariant</span>());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意点：</p><ul><li><strong>合并单元格</strong>：通过 <code>dynamicCall(&quot;Merge&quot;)</code> 合并单元格。</li><li><strong>设置合并后单元格样式</strong>：可以设置合并后的单元格样式，如对齐方式和字体。</li></ul><h3 id="mergeSameRefResCells-函数：合并某一列连续相同值的单元格"><a href="#mergeSameRefResCells-函数：合并某一列连续相同值的单元格" class="headerlink" title="mergeSameRefResCells() 函数：合并某一列连续相同值的单元格"></a><code>mergeSameRefResCells()</code> 函数：合并某一列连续相同值的单元格</h3><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">ExportTask::mergeSameRefResCells</span><span class="params">(QAxObject* table, <span class="type">const</span> QVariantList&amp; measurements)</span> </span>&#123;</span><br><span class="line">    QString prevRefRes;</span><br><span class="line">    <span class="type">int</span> startRow = <span class="number">2</span>;</span><br><span class="line">    <span class="type">int</span> currentRow = <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line">    foreach (<span class="type">const</span> QVariant&amp; measurementVariant, measurements) &#123;</span><br><span class="line">        QVariantMap measurement = measurementVariant.<span class="built_in">toMap</span>();</span><br><span class="line">        QString currentRefRes = measurement[<span class="string">&quot;refRes&quot;</span>].<span class="built_in">toString</span>();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (currentRefRes == prevRefRes) &#123;</span><br><span class="line">            QAxObject* currentCell = table-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Cell(int, int)&quot;</span>, currentRow, <span class="number">2</span>);</span><br><span class="line">            QAxObject* currentRange = currentCell-&gt;<span class="built_in">querySubObject</span>(<span class="string">&quot;Range&quot;</span>);</span><br><span class="line">            currentRange-&gt;<span class="built_in">setProperty</span>(<span class="string">&quot;Text&quot;</span>, <span class="string">&quot;&quot;</span>);</span><br><span class="line">            <span class="keyword">delete</span> currentRange;</span><br><span class="line">            <span class="keyword">delete</span> currentCell;</span><br><span class="line"></span><br><span class="line">            currentRow++;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (startRow &lt; currentRow) &#123;</span><br><span class="line">                <span class="built_in">MergeCells</span>(table, startRow, <span class="number">2</span>, currentRow - <span class="number">1</span>, <span class="number">2</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            startRow = currentRow;</span><br><span class="line">            currentRow++;</span><br><span class="line">        &#125;</span><br><span class="line">        prevRefRes = currentRefRes;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (startRow &lt; currentRow) &#123;</span><br><span class="line">        <span class="built_in">MergeCells</span>(table, startRow, <span class="number">2</span>, currentRow - <span class="number">1</span>, <span class="number">2</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注意点：</p><ul><li><strong>遍历测量数据</strong>：通过遍历测量数据找到相同值的单元格。</li><li><strong>条件合并</strong>：如果发现相同值，将这些单元格合并。</li></ul><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><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></pre></td><td class="code"><pre><span class="line">QAxBase: Error calling IDispatch member Add: Exception thrown by server</span><br><span class="line">QAxBase::dynamicCallHelper: Object does <span class="keyword">not</span> support automation</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>如果遇到以上错误，请尝试执行以下操作：</p><ul><li><code>QAxObject</code> 在多线程中的初始化及调用代码必须放在同一个线程中。</li><li>不能在子线程中使用 <code>QAxWidget</code>，<code>QAxWidget</code> 继承至 <code>QWidget</code> 类，不能在子线程中执行有关主线程的 UI 界面的操作。</li><li>在操作模板时，有些格式会影响 <code>QAxObject</code> 的正常使用，如合并单元格时，需要原始表格含有边框，否则会报错。</li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过子线程和 <code>QAxObject</code> 生成 Word 文档，能够提高应用的响应速度，并避免阻塞主线程。在实际应用中，注意处理异常情况，并确保所有 <code>QAxObject</code> 对象在使用后适时删除，以避免资源泄漏。</p>]]>
    </content>
    <id>https://iming.eu.org/2024/06/12/qt-export-word/</id>
    <link href="https://iming.eu.org/2024/06/12/qt-export-word/"/>
    <published>2024-06-12T07:00:00.000Z</published>
    <summary>使用 QAxObject 在 Qt 中导出 Word 文档的非详细指南。</summary>
    <title>QAxObject 类导出 Word</title>
    <updated>2026-05-18T03:22:11.259Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="VPS" scheme="https://iming.eu.org/categories/VPS/"/>
    <category term="fail2ban" scheme="https://iming.eu.org/tags/fail2ban/"/>
    <category term="SSH" scheme="https://iming.eu.org/tags/SSH/"/>
    <category term="安全" scheme="https://iming.eu.org/tags/%E5%AE%89%E5%85%A8/"/>
    <category term="Linux" scheme="https://iming.eu.org/tags/Linux/"/>
    <content>
      <![CDATA[<h2 id="修改-SSH-端口"><a href="#修改-SSH-端口" class="headerlink" title="修改 SSH 端口"></a>修改 SSH 端口</h2><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">编辑 ssh 配置文件</span></span><br><span class="line">vim /etc/ssh/sshd_config</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">sshd_config 文档内容</span></span><br><span class="line">port 2222</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">注意还有英文冒号  w：保存 q：退出</span></span><br><span class="line">:wq</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启 ssh</span></span><br><span class="line">systemctl restart ssh</span><br></pre></td></tr></table></figure><h2 id="fail2ban-禁用-IP"><a href="#fail2ban-禁用-IP" class="headerlink" title="fail2ban 禁用 IP"></a>fail2ban 禁用 IP</h2><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">安装 fail2ban iptables vim  -y：自动选择<span class="built_in">yes</span></span></span><br><span class="line">apt install fail2ban iptables vim -y</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动 fail2ban</span></span><br><span class="line">systemctl start fail2ban</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">开启自启 fail2ban</span></span><br><span class="line">systemctl enable fail2ban</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看 fail2ban 状态（出现绿色的字 active (running) 表示正常运行）</span></span><br><span class="line">systemctl status fail2ban</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建并编辑 fail2ban 配置文件（.<span class="built_in">local</span>文件会覆盖.conf相同参数的文件，所以只需要修改.<span class="built_in">local</span>即可）</span></span><br><span class="line">vim /etc/fail2ban/jail.local</span><br></pre></td></tr></table></figure><figure class="highlight ini"><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="section">[sshd]</span></span><br><span class="line"><span class="attr">enabled</span> = <span class="literal">true</span></span><br><span class="line"><span class="attr">port</span> = <span class="number">2222</span></span><br><span class="line"><span class="attr">findtime</span> = <span class="number">120</span>m</span><br><span class="line"><span class="attr">maxretry</span> = <span class="number">3</span></span><br><span class="line"><span class="attr">bantime</span> = <span class="number">365</span>d</span><br><span class="line"><span class="attr">ignoreip</span> = <span class="number">192.168</span>.<span class="number">0.0</span>/<span class="number">16</span> <span class="number">10.0</span>.<span class="number">0.0</span>/<span class="number">8</span> <span class="number">172.16</span>.<span class="number">0.0</span>/<span class="number">12</span> <span class="number">127.0</span>.<span class="number">0.1</span>/<span class="number">8</span> ::<span class="number">1</span></span><br><span class="line"><span class="attr">logpath</span> = /var/log/auth.log</span><br><span class="line"><span class="attr">backend</span> = %(sshd_backend)s</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">#重载生效</span></span><br><span class="line">systemctl restart fail2ban</span><br><span class="line"></span><br><span class="line">systemctl status fail2ban</span><br><span class="line"></span><br><span class="line">fail2ban-client status sshd</span><br></pre></td></tr></table></figure><h2 id="常用命令"><a href="#常用命令" class="headerlink" title="常用命令"></a>常用命令</h2><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">检查日志</span></span><br><span class="line">fail2ban-client status sshd</span><br><span class="line">cat /var/log/fail2ban.log</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">解封 IP</span></span><br><span class="line">fail2ban-client set sshd unbanip 127.0.0.1</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">封禁 IP</span></span><br><span class="line">sudo fail2ban-client set sshd banip xxx.xxx.xxx.xxx</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://iming.eu.org/2024/04/15/fail2ban/</id>
    <link href="https://iming.eu.org/2024/04/15/fail2ban/"/>
    <published>2024-04-15T02:00:00.000Z</published>
    <summary>修改 SSH 端口，使用 fail2ban 禁用恶意登录 IP。</summary>
    <title>fail2ban 有效配置</title>
    <updated>2026-05-18T03:22:11.231Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="Qt" scheme="https://iming.eu.org/categories/Qt/"/>
    <category term="静态编译" scheme="https://iming.eu.org/tags/%E9%9D%99%E6%80%81%E7%BC%96%E8%AF%91/"/>
    <category term="OpenSSL" scheme="https://iming.eu.org/tags/OpenSSL/"/>
    <category term="MSVC" scheme="https://iming.eu.org/tags/MSVC/"/>
    <content>
      <![CDATA[<h2 id="前置要求"><a href="#前置要求" class="headerlink" title="前置要求"></a>前置要求</h2><p>已经静态编译好的 OpenSSL 库，存放在 <code>C:\Program Files (x86)\OpenSSL</code> 下：</p><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><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">├─bin</span><br><span class="line">├─html</span><br><span class="line">│  ├─man1</span><br><span class="line">│  ├─man3</span><br><span class="line">│  ├─man5</span><br><span class="line">│  └─man7</span><br><span class="line">├─include</span><br><span class="line">│  └─openssl</span><br><span class="line">└─lib</span><br><span class="line"><span class="code">    └─engines-1_1</span></span><br></pre></td></tr></table></figure><p>Qt 5.15.2 镜像：<br><a href="https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.15/5.15.2/single/qt-everywhere-src-5.15.2.zip">https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.15/5.15.2/single/qt-everywhere-src-5.15.2.zip</a></p><h2 id="执行脚本编译"><a href="#执行脚本编译" class="headerlink" title="执行脚本编译"></a>执行脚本编译</h2><h3 id="运行-x86-Native-Tools-Command-Prompt-for-VS-2019"><a href="#运行-x86-Native-Tools-Command-Prompt-for-VS-2019" class="headerlink" title="运行 x86 Native Tools Command Prompt for VS 2019"></a>运行 x86 Native Tools Command Prompt for VS 2019</h3><h3 id="进入-PowerShell"><a href="#进入-PowerShell" class="headerlink" title="进入 PowerShell"></a>进入 PowerShell</h3><h3 id="输入-Set-ExecutionPolicy-Unrestricted"><a href="#输入-Set-ExecutionPolicy-Unrestricted" class="headerlink" title="输入 Set-ExecutionPolicy Unrestricted"></a>输入 Set-ExecutionPolicy Unrestricted</h3><h3 id="msvc2019-build5-15-2-static-ps1"><a href="#msvc2019-build5-15-2-static-ps1" class="headerlink" title=".\msvc2019-build5.15.2-static.ps1"></a>.\msvc2019-build5.15.2-static.ps1</h3><h3 id="PowerShell-脚本（可在编译时自行选择-configure-配置参数）："><a href="#PowerShell-脚本（可在编译时自行选择-configure-配置参数）：" class="headerlink" title="PowerShell 脚本（可在编译时自行选择 configure 配置参数）："></a>PowerShell 脚本（可在编译时自行选择 configure 配置参数）：</h3><figure class="highlight powershell"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># OpenSSL</span></span><br><span class="line"><span class="comment"># 1.1.1d</span></span><br><span class="line"></span><br><span class="line"><span class="variable">$version_base</span> = <span class="string">&quot;5.15&quot;</span></span><br><span class="line"><span class="variable">$version</span> = <span class="string">&quot;5.15.2&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># $qt_sources_url = &quot;https://download.qt.io/official_releases/qt/&quot; + $version_base + &quot;/&quot; + $version + &quot;/single/qt-everywhere-src-&quot; + $version + &quot;.zip&quot;</span></span><br><span class="line"><span class="variable">$qt_archive_file</span> = <span class="string">&quot;D:\QT\qt\5.15.2\qt-everywhere-src-5.15.2.zip&quot;</span></span><br><span class="line"><span class="variable">$qt_src_base_folder</span> = <span class="variable">$pwd</span>.Path + <span class="string">&quot;\qt-everywhere-src-&quot;</span> + <span class="variable">$version</span></span><br><span class="line"></span><br><span class="line"><span class="variable">$tools_folder</span> = <span class="variable">$pwd</span>.Path + <span class="string">&quot;\tools\&quot;</span></span><br><span class="line"><span class="variable">$type</span> = <span class="string">&quot;static&quot;</span></span><br><span class="line"><span class="variable">$prefix_base_folder</span> = <span class="string">&quot;qt-&quot;</span> + <span class="variable">$version</span> + <span class="string">&quot;-&quot;</span> + <span class="variable">$type</span> + <span class="string">&quot;-msvc2019-x86&quot;</span></span><br><span class="line"><span class="variable">$prefix_folder</span> = <span class="variable">$pwd</span>.Path + <span class="string">&quot;\&quot;</span> + <span class="variable">$prefix_base_folder</span></span><br><span class="line"><span class="variable">$build_folder</span> = <span class="variable">$pwd</span>.Path + <span class="string">&quot;\bld&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="variable">$openssl_base_folder</span> = <span class="string">&quot;C:\Program Files (x86)\OpenSSL&quot;</span></span><br><span class="line"><span class="variable">$openssl_include_folder</span> = <span class="variable">$openssl_base_folder</span> + <span class="string">&quot;\include&quot;</span></span><br><span class="line"><span class="variable">$openssl_libs_folder</span> = <span class="variable">$openssl_base_folder</span> + <span class="string">&quot;\lib&quot;</span></span><br><span class="line"><span class="variable">$openssl_bin_folder</span> = <span class="variable">$openssl_base_folder</span> + <span class="string">&quot;\bin&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Download Qt sources, unpack.</span></span><br><span class="line"><span class="comment"># $AllProtocols = [System.Net.SecurityProtocolType]&#x27;Ssl3,Tls,Tls11,Tls12&#x27;</span></span><br><span class="line"><span class="comment"># [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Invoke-WebRequest -Uri $qt_sources_url -OutFile $qt_archive_file</span></span><br><span class="line">&amp; <span class="string">&quot;<span class="variable">$tools_folder</span>\7za.exe&quot;</span> x <span class="variable">$qt_archive_file</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Configure.</span></span><br><span class="line">mkdir <span class="variable">$build_folder</span></span><br><span class="line"><span class="built_in">cd</span> <span class="variable">$build_folder</span></span><br><span class="line"></span><br><span class="line">&amp; <span class="string">&quot;<span class="variable">$qt_src_base_folder</span>\configure.bat&quot;</span> <span class="literal">-debug-and-release</span> <span class="literal">-opensource</span> <span class="literal">-confirm-license</span> <span class="literal">-platform</span> win32<span class="literal">-msvc</span> <span class="literal">-opengl</span> desktop <span class="literal">-no-iconv</span> <span class="literal">-no-dbus</span> <span class="literal">-no-icu</span> <span class="literal">-no-fontconfig</span> <span class="literal">-no-freetype</span> <span class="literal">-qt-harfbuzz</span> <span class="literal">-qt-doubleconversion</span> <span class="literal">-nomake</span> examples <span class="literal">-nomake</span> tests <span class="literal">-no-feature-d3d12</span> <span class="literal">-skip</span> qt3d <span class="literal">-skip</span> qtactiveqt <span class="literal">-skip</span> qtcanvas3d <span class="literal">-skip</span> qtdatavis3d <span class="literal">-skip</span> qtdoc <span class="literal">-skip</span> qtgamepad <span class="literal">-skip</span> qtgraphicaleffects <span class="literal">-skip</span> qtlocation <span class="literal">-skip</span> qtpurchasing <span class="literal">-skip</span> qtscxml <span class="literal">-skip</span> qtsensors <span class="literal">-skip</span> qtspeech <span class="literal">-skip</span> qtwebview <span class="literal">-skip</span> qtscript <span class="literal">-skip</span> qtwebengine <span class="literal">-mp</span> <span class="literal">-optimize-size</span> <span class="literal">-D</span> <span class="string">&quot;JAS_DLL=0&quot;</span> <span class="literal">-static</span> <span class="literal">-feature-relocatable</span> <span class="literal">-ltcg</span> <span class="literal">-prefix</span> <span class="variable">$prefix_folder</span> <span class="literal">-openssl-linked</span> <span class="literal">-I</span> <span class="variable">$openssl_include_folder</span> <span class="literal">-L</span> <span class="variable">$openssl_libs_folder</span> OPENSSL_LIBS=<span class="string">&quot;-lUser32 -lAdvapi32 -lGdi32 -lWS2_32 -lCRYPT32 -llibcrypto -llibssl&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Compile.</span></span><br><span class="line">nmake</span><br><span class="line">nmake install</span><br><span class="line"></span><br><span class="line"><span class="comment"># Copy OpenSSL.</span></span><br><span class="line"><span class="built_in">cp</span> <span class="string">&quot;<span class="variable">$openssl_libs_folder</span>\*&quot;</span> <span class="string">&quot;<span class="variable">$prefix_folder</span>\lib\&quot;</span> <span class="literal">-Recurse</span></span><br><span class="line"><span class="built_in">cp</span> <span class="string">&quot;<span class="variable">$openssl_include_folder</span>\openssl&quot;</span> <span class="string">&quot;<span class="variable">$prefix_folder</span>\include\&quot;</span> <span class="literal">-Recurse</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Fixup OpenSSL DLL paths and MySQL paths.</span></span><br><span class="line"><span class="variable">$openssl_libs_folder_esc</span> = <span class="variable">$openssl_libs_folder</span> <span class="operator">-replace</span> <span class="string">&#x27;\\&#x27;</span>,<span class="string">&#x27;\\&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">gci</span> <span class="literal">-r</span> <span class="literal">-include</span> <span class="string">&quot;*.prl&quot;</span> <span class="variable">$prefix_folder</span> | <span class="built_in">foreach-object</span> &#123; <span class="variable">$a</span> = <span class="variable">$_</span>.fullname; (<span class="built_in">get-content</span> <span class="variable">$a</span>).Replace(<span class="variable">$openssl_libs_folder_esc</span>, <span class="string">&#x27;$$$$[QT_INSTALL_LIBS]\\&#x27;</span>) | <span class="built_in">set-content</span> <span class="variable">$a</span> &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># Create final archive.</span></span><br><span class="line">&amp; <span class="string">&quot;<span class="variable">$tools_folder</span>\7za.exe&quot;</span> a <span class="literal">-t7z</span> <span class="string">&quot;<span class="variable">$</span>&#123;prefix_base_folder&#125;.7z&quot;</span> <span class="string">&quot;<span class="variable">$prefix_folder</span>&quot;</span> <span class="literal">-mmt</span> <span class="literal">-mx9</span></span><br></pre></td></tr></table></figure><p>上述编译过程可能需要 3 至 4 小时不等，最终输出文件夹 <code>qt-5.15.2-static-msvc2019-x86</code> 即为编译好的源码，导入至 Qt 中使用即可。</p><blockquote><p><a href="https://github.com/martinrotter/qt-minimalistic-builds?tab=readme-ov-file">参考</a></p></blockquote>]]>
    </content>
    <id>https://iming.eu.org/2024/04/13/qt-static-compile-openssl/</id>
    <link href="https://iming.eu.org/2024/04/13/qt-static-compile-openssl/"/>
    <published>2024-04-13T01:30:00.000Z</published>
    <summary>在静态编译版本基础上集成 OpenSSL 库，使用 PowerShell 脚本一键完成构建。</summary>
    <title>Qt 5.15.2 MSVC2019 32 位静态编译（含 OpenSSL）</title>
    <updated>2026-05-18T03:22:11.259Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="Qt" scheme="https://iming.eu.org/categories/Qt/"/>
    <category term="静态编译" scheme="https://iming.eu.org/tags/%E9%9D%99%E6%80%81%E7%BC%96%E8%AF%91/"/>
    <category term="MSVC" scheme="https://iming.eu.org/tags/MSVC/"/>
    <category term="x86" scheme="https://iming.eu.org/tags/x86/"/>
    <content>
      <![CDATA[<h2 id="获取源码"><a href="#获取源码" class="headerlink" title="获取源码"></a>获取源码</h2><p>清华镜像：<br><a href="https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.15/5.15.2/single/qt-everywhere-src-5.15.2.zip">https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.15/5.15.2/single/qt-everywhere-src-5.15.2.zip</a></p><h2 id="编译工具下载-COMPILER-DOWNLOAD"><a href="#编译工具下载-COMPILER-DOWNLOAD" class="headerlink" title="编译工具下载&#x2F;COMPILER DOWNLOAD"></a>编译工具下载&#x2F;COMPILER DOWNLOAD</h2><p>打开源码目录下的 README 文件，查看当前版本 Qt 要求的 Windows 环境下编译需要安装的工具：</p><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><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="section">Windows:</span></span><br><span class="line"><span class="section">--------</span></span><br><span class="line"></span><br><span class="line">  Open a command prompt.</span><br><span class="line">  Ensure that the following tools can be found in the path:</span><br><span class="line"><span class="bullet">  *</span> Supported compiler (Visual Studio 2012 or later,</span><br><span class="line"><span class="code">     MinGW-builds gcc 4.9 or later)</span></span><br><span class="line"><span class="code">  * Perl version 5.12 or later   [http://www.activestate.com/activeperl/]</span></span><br><span class="line"><span class="code">  * Python version 2.7 or later  [http://www.activestate.com/activepython/]</span></span><br><span class="line"><span class="code">  * Ruby version 1.9.3 or later  [http://rubyinstaller.org/]</span></span><br></pre></td></tr></table></figure><h3 id="编译环境选择：MINGW-MSVC"><a href="#编译环境选择：MINGW-MSVC" class="headerlink" title="编译环境选择：MINGW&#x2F;MSVC"></a>编译环境选择：MINGW&#x2F;MSVC</h3><p>在 Windows 上，有两个预构建环境可供选择：一个是 MinGW，另一个是 Microsoft Visual Studio (MSVC)。这两个环境不兼容，无法混合。你必须选择一个。</p><p>这两者的区别如下：</p><p>当你的项目使用 MinGW 编译的使用，想要用一个 MSVC 编译生成的库时就会有问题。使用 MinGW 编译项目的时候，所使用的 Lib 也要是 MinGW 编译的。如果你只是开发 Window 平台的软件时，最好用 Qt MSVC 组合，这样可以使用大量的第三方 lib，还有很多的构建指令，毕竟 window 上 MSVC 才是王道。</p><p>我选择 MSVC，打开安装 VS 时自带安装的 MSCV：<code>x64 Native Tools Command Prompt for VS 2019</code></p><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><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">**********************************************************************</span><br><span class="line">** Visual Studio 2019 Developer Command Prompt v16.4.5</span><br><span class="line">** Copyright (c) 2019 Microsoft Corporation</span><br><span class="line">**********************************************************************</span><br><span class="line">[vcvarsall.bat] Environment initialized <span class="keyword">for</span>: <span class="string">&#x27;x64&#x27;</span></span><br><span class="line"></span><br><span class="line">C:\Program Files (x86)\Microsoft Visual Studio\2019\Community&gt;</span><br></pre></td></tr></table></figure><p>默认编译的结果是 64 位的 Qt</p><p>如果你想编译 32 位版本的 qt，可以选择 <code>x86 Native Tools Command Prompt for VS 2019</code></p><p><em>警告：不要使用 Developer Command Prompt for VS 2019</em></p><p>如果你想在 linux 系统中进行 Qt 的编译工作，参考这个问答：<a href="https://stackoverflow.com/questions/14932315/how-to-compile-qt-5-under-windows-or-linux-32-or-64-bit-static-or-dynamic-on-v">c++ - How to compile Qt 5 under Windows or Linux, 32 or 64 bit, static or dynamic on Visual Studio or g++ - Stack Overflow</a></p><h2 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h2><p>在 D 盘新建一个目录用来存放编译好的内容：<code>D:\qt</code></p><p>在 <code>x64 Native Tools Command Prompt for VS 2019</code> 的终端进入 Qt 源代码目录：</p><figure class="highlight sh"><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">C:\Users\peter\Downloads&gt;<span class="built_in">cd</span> qt-everywhere-src-5.14.1</span><br><span class="line">C:\Users\peter\Downloads\qt-everywhere-src-5.14.1&gt;</span><br></pre></td></tr></table></figure><h3 id="修改源码里的-QTBASE-MKSPECS-COMMON-MSVC-DESKTOP-CONF-文件"><a href="#修改源码里的-QTBASE-MKSPECS-COMMON-MSVC-DESKTOP-CONF-文件" class="headerlink" title="修改源码里的 QTBASE\MKSPECS\COMMON\MSVC-DESKTOP.CONF 文件"></a>修改源码里的 <code>QTBASE\MKSPECS\COMMON\MSVC-DESKTOP.CONF</code> 文件</h3><p>修改 -MD 为 -MT</p><p>修改前：</p><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></pre></td><td class="code"><pre><span class="line">QMAKE_CFLAGS_RELEASE    = $<span class="variable">$QMAKE_CFLAGS_OPTIMIZE</span> -MD</span><br><span class="line">QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $<span class="variable">$QMAKE_CFLAGS_OPTIMIZE</span> -Zi -MD</span><br><span class="line">QMAKE_CFLAGS_DEBUG      = -Zi -MDd</span><br></pre></td></tr></table></figure><p>修改后：</p><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></pre></td><td class="code"><pre><span class="line">QMAKE_CFLAGS_RELEASE    = $<span class="variable">$QMAKE_CFLAGS_OPTIMIZE</span> -MT</span><br><span class="line">QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $<span class="variable">$QMAKE_CFLAGS_OPTIMIZE</span> -Zi -MT</span><br><span class="line">QMAKE_CFLAGS_DEBUG      = -Zi -MTd</span><br></pre></td></tr></table></figure><p>D 的意思是动态编译 (dynamic link)，T 的意思是静态编译（static link）。</p><h3 id="配置-CONFIG-文件："><a href="#配置-CONFIG-文件：" class="headerlink" title="配置 CONFIG 文件："></a>配置 CONFIG 文件：</h3><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">configure.bat -prefix D:\QT\qt\5.15.2\msvc2019_32_static -confirm-license -opensource -debug-and-release -static -static-runtime -no-feature-d3d12 -platform win32-msvc -mp -nomake tests -nomake examples -nomake tools -gui -widgets -plugin-sql-sqlite</span><br></pre></td></tr></table></figure><p>具体含义如下：</p><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><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">configure.bat</span><br><span class="line">-static <span class="comment">#指明是静态编译</span></span><br><span class="line">-prefix <span class="string">&quot;D:\qt&quot;</span> <span class="comment">#指明安装的目录</span></span><br><span class="line">-confirm-license -opensource  <span class="comment">#指明是开源版本的qt</span></span><br><span class="line">-debug-and-release <span class="comment">#指明需要debug版和release版，可以单独选择release版</span></span><br><span class="line">-platform win32-msvc  <span class="comment">#指明使用msvc编译，这里的win32并不指32位</span></span><br><span class="line">-nomake examples -nomake tests  <span class="comment">#不编译样例</span></span><br><span class="line">-plugin-sql-sqlite -plugin-sql-odbc -qt-zlib -qt-libpng -qt-libjpeg <span class="comment">#可选插件</span></span><br><span class="line">-opengl desktop  <span class="comment">#用系统自带的opengl</span></span><br><span class="line">-mp <span class="comment">#多核编译</span></span><br></pre></td></tr></table></figure><h3 id="MAKE"><a href="#MAKE" class="headerlink" title="MAKE"></a>MAKE</h3><p>上面提到过在 Windows 上，有两个预构建环境可供选择：一个是 MinGW，另一个是 Microsoft Visual Studio (MSVC)。</p><p>我选择的是 msvc 环境，使用命令 nmake 即可进行编译。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nmake</span><br></pre></td></tr></table></figure><p>新版的 MSVC 可以进行多线程编译，旧版本的 MSVC 自带的 nmake 没有多线程编译功能，有一个替代功能的软件 <strong>jom</strong> 可以进行 nmake 的多线程编译。</p><p>jom 的下载地址：<a href="https://wiki.qt.io/Jom">Jom - Qt Wiki</a></p><p>在刚才的终端中运行命令：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">D</span>:<span class="regexp">/jom_1_1_3/</span>jom.<span class="property">exe</span></span><br></pre></td></tr></table></figure><h3 id="MAKE-INSTALL"><a href="#MAKE-INSTALL" class="headerlink" title="MAKE INSTALL"></a>MAKE INSTALL</h3><p>使用 nmake 单线程 install：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nmake install</span><br></pre></td></tr></table></figure><h2 id="添加到-QT-CREATOR"><a href="#添加到-QT-CREATOR" class="headerlink" title="添加到 QT CREATOR"></a>添加到 QT CREATOR</h2><h3 id="添加-QT-VERSIONS"><a href="#添加-QT-VERSIONS" class="headerlink" title="添加 QT VERSIONS"></a>添加 QT VERSIONS</h3><p><a class="pswp-link" href="/2024/04/13/qt-static-compile/Qt_versions.large.webp" data-pswp-width="980" data-pswp-height="565" target="_blank" rel="noopener"><img src="/2024/04/13/qt-static-compile/Qt_versions.thumb.webp" width="980" height="565" alt="" loading="lazy" decoding="async"></a></p><p><code>注：若新增 qmake.exe 前出现黄色感叹号，可复制其它版本 bin 目录下的 qmlscene.exe 到该静态编译版本的 bin 目录下即可。</code></p><h3 id="新建构建套件"><a href="#新建构建套件" class="headerlink" title="新建构建套件"></a>新建构建套件</h3><p>新建构建套件，Qt 版本选择刚添加的静态版，记得编译器选自己编译时用的编译器。</p><p><a class="pswp-link" href="/2024/04/13/qt-static-compile/QtKits.large.webp" data-pswp-width="980" data-pswp-height="565" target="_blank" rel="noopener"><img src="/2024/04/13/qt-static-compile/QtKits.thumb.webp" width="980" height="565" alt="" loading="lazy" decoding="async"></a></p><blockquote><p><a href="https://blog.csdn.net/qq_45423146/article/details/120148288">Qt5.15.2 msvc 静态编译记录_-platform win32-msvc_themql 的博客-CSDN 博客</a></p></blockquote><blockquote><p><a href="https://www.freesion.com/article/2780388306/">Qt 最新版 5.14 在 Windows 环境静态编译安装和部署的完整过程 VS 2019-Qt static link build Windows 32 bit&#x2F;64 bit - 灰信网（软件开发博客聚合）(freesion.com)</a></p></blockquote><blockquote><p><a href="/2024/04/13/qt-static-compile-openssl/">带 OpenSSL 库的静态编译版本</a></p></blockquote>]]>
    </content>
    <id>https://iming.eu.org/2024/04/13/qt-static-compile/</id>
    <link href="https://iming.eu.org/2024/04/13/qt-static-compile/"/>
    <published>2024-04-13T01:00:00.000Z</published>
    <summary>Qt 官方不提供静态编译好的安装包，所以需要我们在自己的电脑上静态编译。</summary>
    <title>Qt 5.15.2 MSVC2019 32 位静态编译</title>
    <updated>2026-05-18T03:22:11.263Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="Qt" scheme="https://iming.eu.org/categories/Qt/"/>
    <category term="在线更新" scheme="https://iming.eu.org/tags/%E5%9C%A8%E7%BA%BF%E6%9B%B4%E6%96%B0/"/>
    <category term="软件升级" scheme="https://iming.eu.org/tags/%E8%BD%AF%E4%BB%B6%E5%8D%87%E7%BA%A7/"/>
    <category term="QNetworkAccessManager" scheme="https://iming.eu.org/tags/QNetworkAccessManager/"/>
    <content>
      <![CDATA[<h2 id="检查更新"><a href="#检查更新" class="headerlink" title="检查更新"></a>检查更新</h2><p>首先，我们需要一个函数来检查是否有新的版本可用。在这个例子中，我们使用 <code>QNetworkAccessManager</code> 来发送一个 GET 请求到我们的更新服务器。我们将当前的版本号作为查询参数添加到 URL 中。</p><figure class="highlight c++"><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="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">QApplication <span class="title">a</span><span class="params">(argc, argv)</span></span>;</span><br><span class="line"></span><br><span class="line">    QString version = <span class="string">&quot;1.0.1&quot;</span>;</span><br><span class="line">    a.<span class="built_in">setApplicationVersion</span>(version);</span><br><span class="line"></span><br><span class="line">    MainWindow w;</span><br><span class="line">    w.<span class="built_in">show</span>();</span><br><span class="line">    <span class="keyword">return</span> a.<span class="built_in">exec</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">MainWindow::checkForUpdates</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    QNetworkAccessManager *manager = <span class="keyword">new</span> <span class="built_in">QNetworkAccessManager</span>(<span class="keyword">this</span>);</span><br><span class="line">    <span class="built_in">connect</span>(manager, &amp;QNetworkAccessManager::finished, <span class="keyword">this</span>, &amp;MainWindow::onCheckForUpdatesFinished);</span><br><span class="line"></span><br><span class="line">    <span class="function">QUrl <span class="title">url</span><span class="params">(<span class="string">&quot;https://XXX.XX/XXX/index.php/Home/Update/XXX&quot;</span>)</span></span>;</span><br><span class="line">    QUrlQuery query;</span><br><span class="line">    query.<span class="built_in">addQueryItem</span>(<span class="string">&quot;version&quot;</span>, QApplication::<span class="built_in">applicationVersion</span>());</span><br><span class="line">    url.<span class="built_in">setQuery</span>(query);</span><br><span class="line"></span><br><span class="line">    QSslConfiguration config = QSslConfiguration::<span class="built_in">defaultConfiguration</span>();</span><br><span class="line">    config.<span class="built_in">setPeerVerifyMode</span>(QSslSocket::VerifyNone);</span><br><span class="line">    config.<span class="built_in">setProtocol</span>(QSsl::AnyProtocol);</span><br><span class="line"></span><br><span class="line">    <span class="function">QNetworkRequest <span class="title">request</span><span class="params">(url)</span></span>;</span><br><span class="line">    request.<span class="built_in">setSslConfiguration</span>(config);</span><br><span class="line"></span><br><span class="line">    manager-&gt;<span class="built_in">get</span>(request);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="处理服务器的响应"><a href="#处理服务器的响应" class="headerlink" title="处理服务器的响应"></a>处理服务器的响应</h2><p>当我们收到服务器的响应时，我们需要解析它来确定是否有新的版本可用。在这个例子中，我们假设服务器返回一个 JSON 对象，其中包含一个 <code>updateFileUrl</code> 字段，这个字段指向新版本的下载链接。</p><figure class="highlight c++"><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="function"><span class="type">void</span> <span class="title">MainWindow::onCheckForUpdatesFinished</span><span class="params">(QNetworkReply *reply)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (reply-&gt;<span class="built_in">error</span>() == QNetworkReply::NoError) &#123;</span><br><span class="line">        QJsonDocument jsonDoc = QJsonDocument::<span class="built_in">fromJson</span>(reply-&gt;<span class="built_in">readAll</span>());</span><br><span class="line">        QJsonObject jsonObj = jsonDoc.<span class="built_in">object</span>();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (jsonObj.<span class="built_in">contains</span>(<span class="string">&quot;updateFileUrl&quot;</span>)) &#123;</span><br><span class="line">            QString downloadLink = jsonObj[<span class="string">&quot;updateFileUrl&quot;</span>].<span class="built_in">toString</span>();</span><br><span class="line">            QString latestVersion = jsonObj[<span class="string">&quot;latestVersion&quot;</span>].<span class="built_in">toString</span>();</span><br><span class="line">            QString updateContent = jsonObj[<span class="string">&quot;updateContent&quot;</span>].<span class="built_in">toString</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">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    reply-&gt;<span class="built_in">deleteLater</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="下载新版本"><a href="#下载新版本" class="headerlink" title="下载新版本"></a>下载新版本</h2><p>如果用户选择更新，我们开始下载新版本的软件。我们再次使用 <code>QNetworkAccessManager</code> 来发送一个 GET 请求到新版本的下载链接。</p><figure class="highlight c++"><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="function"><span class="type">void</span> <span class="title">MainWindow::onDownloadFinished</span><span class="params">(QNetworkReply *reply)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (reply-&gt;<span class="built_in">error</span>() == QNetworkReply::NoError) &#123;</span><br><span class="line">        QUrl url = reply-&gt;<span class="built_in">url</span>();</span><br><span class="line">        QString filename = <span class="built_in">QFileInfo</span>(url.<span class="built_in">path</span>()).<span class="built_in">fileName</span>();</span><br><span class="line">        QString newFilePath = QCoreApplication::<span class="built_in">applicationDirPath</span>() + <span class="string">&quot;/&quot;</span> + filename;</span><br><span class="line">        <span class="function">QFile <span class="title">file</span><span class="params">(newFilePath)</span></span>;</span><br><span class="line">        <span class="keyword">if</span> (file.<span class="built_in">open</span>(QIODevice::WriteOnly)) &#123;</span><br><span class="line">            file.<span class="built_in">write</span>(reply-&gt;<span class="built_in">readAll</span>());</span><br><span class="line">            file.<span class="built_in">close</span>();</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 启动新版本的软件，并关闭当前的软件</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    reply-&gt;<span class="built_in">deleteLater</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="启动新版本"><a href="#启动新版本" class="headerlink" title="启动新版本"></a>启动新版本</h2><p>最后，我们启动新版本的软件，并关闭当前的软件。</p><figure class="highlight c++"><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">QProcess process;</span><br><span class="line">process.<span class="built_in">setProgram</span>(newFilePath);</span><br><span class="line">process.<span class="built_in">startDetached</span>();</span><br><span class="line"></span><br><span class="line">QApplication::<span class="built_in">quit</span>();</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://iming.eu.org/2024/04/12/qt-software-update/</id>
    <link href="https://iming.eu.org/2024/04/12/qt-software-update/"/>
    <published>2024-04-12T16:00:00.000Z</published>
    <summary>在许多情况下，我们希望我们的软件能够自动检查更新，并在有新版本时提示用户。</summary>
    <title>Qt 实现软件在线更新</title>
    <updated>2026-05-18T03:22:11.259Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="Qt" scheme="https://iming.eu.org/categories/Qt/"/>
    <category term="Xlsx" scheme="https://iming.eu.org/tags/Xlsx/"/>
    <category term="QXlsx" scheme="https://iming.eu.org/tags/QXlsx/"/>
    <content>
      <![CDATA[<h2 id="QT-中动态-xlsx-库的使用"><a href="#QT-中动态-xlsx-库的使用" class="headerlink" title="QT 中动态 xlsx 库的使用"></a>QT 中动态 xlsx 库的使用</h2><p>打开 qxlsx.pro</p><p>选择对应套件进行构建</p><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/1.large.webp" data-pswp-width="860" data-pswp-height="565" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/1.thumb.webp" width="860" height="565" alt="" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/2.large.webp" data-pswp-width="1239" data-pswp-height="562" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/2.thumb.webp" width="1239" height="562" alt="" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/3.large.webp" data-pswp-width="1421" data-pswp-height="598" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/3.thumb.webp" width="1280" height="539" alt="" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/4.large.webp" data-pswp-width="1448" data-pswp-height="590" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/4.thumb.webp" width="1280" height="522" alt="" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/5.large.webp" data-pswp-width="1347" data-pswp-height="591" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/5.thumb.webp" width="1280" height="562" alt="" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/6.large.webp" data-pswp-width="1392" data-pswp-height="578" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/6.thumb.webp" width="1280" height="531" alt="" loading="lazy" decoding="async"></a></p><h2 id="QT-中静态编译-xlsx-库的使用"><a href="#QT-中静态编译-xlsx-库的使用" class="headerlink" title="QT 中静态编译 xlsx 库的使用"></a>QT 中静态编译 xlsx 库的使用</h2><ul><li><p>下载源码</p><ul><li><code>Git</code>：<code>git clone git@github.com:QtExcel/QXlsx.git</code></li></ul></li><li><p>打开 QXlsx 工程：进入 QXlsx 文件夹，双击打开 <code>QXlsx.pro</code> 工程文件</p></li></ul><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/QXlsx1.large.webp" data-pswp-width="869" data-pswp-height="508" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/QXlsx1.thumb.webp" width="869" height="508" alt="" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/QXlsx2.large.webp" data-pswp-width="641" data-pswp-height="225" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/QXlsx2.thumb.webp" width="641" height="225" alt="" loading="lazy" decoding="async"></a></p><ul><li>在 Pro 文件中删除 <code>TARGET = QXlsx</code>，然后加入下列代码，这些代码是将编译后的静态库全部放到一个文件夹下，不用我们自己去拷，同时在编译 debug 版本静态库时在名称后面加一个 <code>d</code> 用于区分，防止 debug 静态库覆盖了 release 静态库。</li></ul><figure class="highlight makefile"><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">contains(QT_ARCH, i386)&#123;        <span class="comment"># 使用32位编译器</span></span><br><span class="line">DESTDIR = $$PWD/bin             <span class="comment"># 程序输出路径</span></span><br><span class="line">&#125;<span class="keyword">else</span>&#123;</span><br><span class="line">message(<span class="string">&quot;64bit&quot;</span>)                <span class="comment"># 使用64位编译器</span></span><br><span class="line">DESTDIR = $$PWD/bin64</span><br><span class="line">&#125;</span><br><span class="line"><span class="section">win32:CONFIG(release, debug|release): TARGET = QXlsx        # 生成release版本静态库名称</span></span><br><span class="line"><span class="section">else:win32:CONFIG(debug, debug|release): TARGET = QXlsxd    # 生成debug版本静态库名称</span></span><br></pre></td></tr></table></figure><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/QXlsx3.large.webp" data-pswp-width="805" data-pswp-height="315" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/QXlsx3.thumb.webp" width="805" height="315" alt="" loading="lazy" decoding="async"></a></p><ul><li><p>分别选择 <code>Debug、Release</code>，然后点击左下角的 <strong>锤子</strong></p></li><li><p>编译完成后，在 QXlsx 文件夹下就会出现一个 bin 文件夹，打开文件夹就可以看见有 <code>QXlsx.lib</code> 和 <code>QXlsxd.lib</code> 两个文件。</p></li></ul><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/QXlsx4.large.webp" data-pswp-width="1140" data-pswp-height="559" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/QXlsx4.thumb.webp" width="1140" height="559" alt="" loading="lazy" decoding="async"></a></p><ul><li><p>将整个 bin 文件和 header 文件复制到一个新建 QXlsx 文件夹中，并把 header 重命名为 include。然后将 QXlsx 文件夹放到项目的目录文件下，这与使用动态库的方式不同。</p><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/QXlsx5.large.webp" data-pswp-width="1140" data-pswp-height="599" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/QXlsx5.thumb.webp" width="1140" height="599" alt="" loading="lazy" decoding="async"></a></p></li><li><p>在 <a href="https://so.csdn.net/so/search?q=QtCreator&spm=1001.2101.3001.7020">QtCreator</a> 中鼠标在工程上右键选择 <strong>添加库</strong></p></li></ul><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/QXlsx6.large.webp" data-pswp-width="516" data-pswp-height="383" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/QXlsx6.thumb.webp" width="516" height="383" alt="" loading="lazy" decoding="async"></a></p><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/QXlsx7.large.webp" data-pswp-width="516" data-pswp-height="511" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/QXlsx7.thumb.webp" width="516" height="511" alt="" loading="lazy" decoding="async"></a></p><ul><li>点击下一步后就会在 Pro 文件中生成内容，将其修改为如下格式</li></ul><p><a class="pswp-link" href="/2024/04/12/qt-xlsx/QXlsx8.large.webp" data-pswp-width="646" data-pswp-height="153" target="_blank" rel="noopener"><img src="/2024/04/12/qt-xlsx/QXlsx8.thumb.webp" width="646" height="153" alt="" loading="lazy" decoding="async"></a></p><blockquote><p>参考 <a href="https://blog.csdn.net/qq_43627907/article/details/124179912">Qt 读写 Excel–QXlsx 编译为静态库</a></p></blockquote>]]>
    </content>
    <id>https://iming.eu.org/2024/04/12/qt-xlsx/</id>
    <link href="https://iming.eu.org/2024/04/12/qt-xlsx/"/>
    <published>2024-04-12T07:30:00.000Z</published>
    <summary>介绍 QXlsx 在 Qt 中的动态使用方式以及如何编译为静态库后集成到工程。</summary>
    <title>Qt-Xlsx 的导入和使用</title>
    <updated>2026-05-18T03:22:11.263Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="Qt" scheme="https://iming.eu.org/categories/Qt/"/>
    <category term="BLE" scheme="https://iming.eu.org/tags/BLE/"/>
    <category term="Bluetooth" scheme="https://iming.eu.org/tags/Bluetooth/"/>
    <content>
      <![CDATA[<blockquote><p>在 Qt 中，通过蓝牙搜索和连接设备的步骤如下：</p></blockquote><h2 id="搜索设备"><a href="#搜索设备" class="headerlink" title="搜索设备"></a>搜索设备</h2><figure class="highlight c++"><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">QBluetoothDeviceDiscoveryAgent *discoveryAgent;</span><br><span class="line">discoveryAgent = <span class="keyword">new</span> <span class="built_in">QBluetoothDeviceDiscoveryAgent</span>(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 开始搜索设备</span></span><br><span class="line">discoveryAgent-&gt;<span class="built_in">start</span>();</span><br></pre></td></tr></table></figure><p>当设备被搜索到时，<code>deviceDiscovered</code>信号会被触发，可以在槽函数中处理新发现的设备。</p><h2 id="连接设备"><a href="#连接设备" class="headerlink" title="连接设备"></a>连接设备</h2><p>选择一个设备进行连接。</p><figure class="highlight c++"><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">QLowEnergyController *controller = <span class="keyword">new</span> <span class="built_in">QLowEnergyController</span>(address);</span><br><span class="line"><span class="built_in">connect</span>(controller, &amp;QLowEnergyController::connected, <span class="keyword">this</span>, &amp;MainWindow::controllerConnected);</span><br><span class="line">controller-&gt;<span class="built_in">connectToDevice</span>();</span><br></pre></td></tr></table></figure><p>可以连接<code>connected</code>信号，以便在设备连接后进行后续操作。</p><h2 id="发现服务"><a href="#发现服务" class="headerlink" title="发现服务"></a>发现服务</h2><p>连接成功后，可以发现设备的所有服务。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">controller-&gt;<span class="built_in">discoverServices</span>();</span><br></pre></td></tr></table></figure><p>服务被发现后，<code>serviceDiscovered</code>信号会被触发。</p><h2 id="特性操作"><a href="#特性操作" class="headerlink" title="特性操作"></a>特性操作</h2><p>可以通过<code>writeCharacteristic</code>函数来写特性，或者使用<code>readCharacteristic</code>来读特性。也可以连接<code>characteristicChanged</code>信号来实时获取。</p>]]>
    </content>
    <id>https://iming.eu.org/2024/04/11/qt-ble/</id>
    <link href="https://iming.eu.org/2024/04/11/qt-ble/"/>
    <published>2024-04-11T07:33:00.000Z</published>
    <summary>在 Qt 中，通过蓝牙搜索和连接设备的简要步骤。</summary>
    <title>BLE 设备搜索与连接示例</title>
    <updated>2026-05-18T03:22:11.259Z</updated>
  </entry>
  <entry>
    <author>
      <name>Ming</name>
    </author>
    <category term="Qt" scheme="https://iming.eu.org/categories/Qt/"/>
    <category term="Modbus" scheme="https://iming.eu.org/tags/Modbus/"/>
    <category term="CRC16" scheme="https://iming.eu.org/tags/CRC16/"/>
    <content>
      <![CDATA[<p>在 Qt 中，如果你需要生成 Modbus CRC16 的校验码，你可以使用以下的方法：</p><p>首先，你需要有一个 CRC16 计算函数，代码如下：</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">uint16_t</span> <span class="title">ModbusCRC16</span><span class="params">(QByteArray senddata)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> len=senddata.<span class="built_in">size</span>();</span><br><span class="line">    <span class="type">uint16_t</span> wcrc=<span class="number">0XFFFF</span>;</span><br><span class="line">    <span class="type">uint8_t</span> temp;</span><br><span class="line">    <span class="type">int</span> i=<span class="number">0</span>,j=<span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span>(i=<span class="number">0</span>;i&lt;len;i++)</span><br><span class="line">    &#123;</span><br><span class="line">        temp=senddata.<span class="built_in">at</span>(i);</span><br><span class="line">        wcrc^=temp;</span><br><span class="line">        <span class="keyword">for</span>(j=<span class="number">0</span>;j&lt;<span class="number">8</span>;j++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(wcrc&amp;<span class="number">0X0001</span>)&#123;</span><br><span class="line">                wcrc&gt;&gt;=<span class="number">1</span>;</span><br><span class="line">                wcrc^=<span class="number">0XA001</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                wcrc&gt;&gt;=<span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    temp=wcrc;</span><br><span class="line">    <span class="keyword">return</span> wcrc;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这是一个可以计算数据的 CRC16 函数，预设的 16 位 crc 寄存器初值全部为 1。</p><p>在使用中，通常我们将一串 16 进制字符串转化为字节流后调用函数，生成 crc 校验码：</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></pre></td><td class="code"><pre><span class="line">QString hexDataString =  head + address + num + sum + hexString1;</span><br><span class="line"><span class="built_in">qDebug</span>() &lt;&lt; hexDataString;</span><br><span class="line">QStringList hexDataList = hexDataString.<span class="built_in">split</span>(<span class="string">&quot; &quot;</span>);</span><br><span class="line">QByteArray byteArray;</span><br><span class="line"></span><br><span class="line">foreach (<span class="type">const</span> QString&amp; hexByte, hexDataList) &#123;</span><br><span class="line">    <span class="type">bool</span> ok;</span><br><span class="line">    <span class="type">int</span> value = hexByte.<span class="built_in">toInt</span>(&amp;ok, <span class="number">16</span>);</span><br><span class="line">    <span class="keyword">if</span> (ok) &#123;</span><br><span class="line">        byteArray.<span class="built_in">append</span>(<span class="built_in">static_cast</span>&lt;<span class="type">char</span>&gt;(value));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">uint16_t</span> wcrc = <span class="built_in">ModbusCRC16</span>(byteArray);</span><br><span class="line"></span><br><span class="line">QString hexString = <span class="built_in">QString</span>(<span class="string">&quot;%1&quot;</span>).<span class="built_in">arg</span>(wcrc, <span class="number">4</span>, <span class="number">16</span>, <span class="built_in">QLatin1Char</span>(<span class="string">&#x27;0&#x27;</span>));</span><br><span class="line">QString lowByte = hexString.<span class="built_in">mid</span>(hexString.<span class="built_in">length</span>() - <span class="number">2</span>);</span><br><span class="line">QString highByte = hexString.<span class="built_in">left</span>(<span class="number">2</span>);</span><br><span class="line"><span class="keyword">if</span> (lowByte.<span class="built_in">length</span>() &lt; <span class="number">2</span>) &#123;</span><br><span class="line">    lowByte.<span class="built_in">prepend</span>(<span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (highByte.<span class="built_in">length</span>() &lt; <span class="number">2</span>) &#123;</span><br><span class="line">    highByte.<span class="built_in">prepend</span>(<span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line">QString combinedHex = (lowByte + <span class="string">&quot; &quot;</span> + highByte).<span class="built_in">toUpper</span>();</span><br></pre></td></tr></table></figure><p>这段代码首先将十六进制字符串分割为一个列表，然后使用该列表创建一个字节数组。提取生成的 wcrc 的低、高位字节，然后将低、高位字节组合在一起（注意：按照小端方式进行组合，即低字节在前，高字节在后），最后得到校验码字符串。</p>]]>
    </content>
    <id>https://iming.eu.org/2024/04/11/qt-modbus-crc16/</id>
    <link href="https://iming.eu.org/2024/04/11/qt-modbus-crc16/"/>
    <published>2024-04-11T03:50:00.000Z</published>
    <summary>在 Qt 中实现 Modbus CRC16 校验码的计算与十六进制字符串的处理。</summary>
    <title>生成 Modbus CRC16 校验码</title>
    <updated>2026-05-18T03:22:11.259Z</updated>
  </entry>
</feed>
