Files
pages/2022/09/05/trayicon.html
2025-12-31 16:00:29 +00:00

473 lines
42 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>制作程序运行提示标志的历程 | Mayx的博客</title>
<meta name="generator" content="Jekyll v3.9.5" />
<meta property="og:title" content="制作程序运行提示标志的历程" />
<meta name="author" content="mayx" />
<meta property="og:locale" content="zh_CN" />
<meta name="description" content="有图形界面的程序可真是难做啊……" />
<meta property="og:description" content="有图形界面的程序可真是难做啊……" />
<meta property="og:site_name" content="Mayx的博客" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2022-09-05T00:00:00+08:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="制作程序运行提示标志的历程" />
<meta name="google-site-verification" content="huTYdEesm8NaFymixMNqflyCp6Jfvd615j5Wq1i2PHc" />
<meta name="msvalidate.01" content="0ADFCE64B3557DC4DC5F2DC224C5FDDD" />
<meta name="yandex-verification" content="fc0e535abed800be" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"mayx"},"dateModified":"2022-09-05T00:00:00+08:00","datePublished":"2022-09-05T00:00:00+08:00","description":"有图形界面的程序可真是难做啊……","headline":"制作程序运行提示标志的历程","mainEntityOfPage":{"@type":"WebPage","@id":"/2022/09/05/trayicon.html"},"publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"https://avatars0.githubusercontent.com/u/17966333"},"name":"mayx"},"url":"/2022/09/05/trayicon.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="canonical" href="https://mabbs.github.io/2022/09/05/trayicon.html" />
<link type="application/atom+xml" rel="alternate" href="/atom.xml" title="Mayx的博客" />
<link rel="alternate" type="application/rss+xml" title="Mayx的博客(RSS)" href="/rss.xml" />
<link rel="alternate" type="application/json" title="Mayx的博客(JSON Feed)" href="/feed.json" />
<link rel="stylesheet" href="/assets/css/style.css?v=1767196818" />
<!--[if !IE]> -->
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
<!-- <![endif]-->
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Mayx的博客" />
<link rel="webmention" href="https://webmention.io/mabbs.github.io/webmention" />
<link rel="pingback" href="https://webmention.io/mabbs.github.io/xmlrpc" />
<link rel="preconnect" href="https://summary.mayx.eu.org" crossorigin="anonymous" />
<link rel="prefetch" href="https://www.blogsclub.org/badge/mabbs.github.io" as="image" />
<link rel="blogroll" type="text/xml" href="/blogroll.opml" />
<link rel="me" href="https://github.com/Mabbs" />
<script src="/assets/js/jquery.min.js"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
var lastUpdated = new Date("Thu, 01 Jan 2026 00:00:18 +0800");
var BlogAPI = "https://summary.mayx.eu.org";
</script>
<script src="/assets/js/main.js"></script>
<!--[if !IE]> -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-137710294-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-137710294-1');
</script>
<script src="/assets/js/instant.page.js" type="module"></script>
<!-- <![endif]-->
</head>
<body>
<!--[if !IE]> --><noscript><marquee style="top: -15px; position: relative;"><small>发现当前浏览器没有启用JavaScript这不影响你的浏览但可能会有一些功能无法使用……</small></marquee></noscript><!-- <![endif]-->
<!--[if IE]><marquee style="top: -15px; position: relative;"><small>发现当前浏览器为Internet Explorer这不影响你的浏览但可能会有一些功能无法使用……</small></marquee><![endif]-->
<div class="wrapper">
<header class="h-card">
<h1><a class="u-url u-uid p-name" rel="me" href="/">Mayx的博客</a></h1>
<img src="https://avatars0.githubusercontent.com/u/17966333" fetchpriority="high" class="u-photo" alt="Logo" style="width: 90%; max-width: 300px; max-height: 300px;" />
<p class="p-note">Mayx's Home Page</p>
<form action="/search.html">
<input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts.." />&#160;<input type="submit" value="搜索" />
</form>
<br />
<p class="view"><a class="u-url" href="/Mabbs/">About me</a></p>
<ul class="downloads">
<li style="width: 270px; border-right: none;"><a href="/MayxBlog.tgz">Download <strong>TGZ File</strong></a></li>
</ul>
</header>
<section class="h-entry">
<small><time class="date dt-published" datetime="2022-09-05T00:00:00+08:00">5 September 2022</time> - 字数统计4273 - 阅读大约需要14分钟 - Hits: <span id="/2022/09/05/trayicon.html" class="visitors">Loading...</span></small>
<h1 class="p-name">制作程序运行提示标志的历程</h1>
<p class="view">by <a class="p-author h-card" href="//github.com/Mabbs">mayx</a></p>
<div id="outdate" style="display:none;">
<hr /><p>
这是一篇创建于 <span id="outime"></span> 天前的文章,其中的信息可能已经有所发展或是发生改变。
</p>
</div>
<script>
daysold = Math.floor((new Date().getTime() - new Date("Mon, 05 Sep 2022 00:00:00 +0800").getTime()) / (24 * 60 * 60 * 1000));
if (daysold > 90) {
document.getElementById("outdate").style.display = "block";
document.getElementById("outime").innerHTML = daysold;
}
</script>
<hr />
<b>AI摘要</b>
<p id="ai-output">这篇文章讲述了作者从使用Python的PyQt5库制作程序运行提示图标遇到体积过大问题到尝试Pystray库结果依然不理想再到最终选择Tkinter和PyQt5实现跨平台悬浮图标过程中的经历。作者在寻求轻量级解决方案时虽然Tkinter在Windows上表现尚可但在Linux上遇到透明度问题而Qt5虽能提供跨平台一致性但学习和使用起来较为复杂。作者对跨平台开发的复杂性以及选择不同工具的权衡有了深入的认识。</p>
<hr />
<ul><li><a href="#起因">起因</a></li><li><a href="#制作的历程">制作的历程</a><ul><li><a href="#使用托盘区图标">使用托盘区图标</a><ul><li><a href="#使用pyqt5库实现">使用PyQt5库实现</a></li><li><a href="#使用pystray库实现">使用pystray库实现</a></li></ul></li><li><a href="#制作悬浮图标">制作悬浮图标</a><ul><li><a href="#通过tkinter实现">通过Tkinter实现</a></li><li><a href="#使用pyqt5库实现-1">使用PyQt5库实现</a></li></ul></li></ul></li><li><a href="#感想">感想</a></li></ul>
<hr />
<main class="post-content e-content" role="main"><p>有图形界面的程序可真是难做啊……<!--more--></p>
<h1 id="起因">
<a href="#起因"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 起因
</h1>
<p>最近我做了一个程序类似于守护进程那样的一个用Python制作的脚本。脚本做出来很简单可是我做出来之后需要向其他人证明我做的脚本正在运行而且是给一个不懂电脑的人知道。在这个前提下我不可能让其他人去看任务管理器、或者执行<code class="language-plaintext highlighter-rouge">ps -ef | grep xxx</code>这种东西吧。所以还是得让它在运行的时候在桌面这样的图形界面显示一些东西才行。</p>
<h1 id="制作的历程">
<a href="#制作的历程"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 制作的历程
</h1>
<h2 id="使用托盘区图标">
<a href="#使用托盘区图标"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 使用托盘区图标
</h2>
<p>像一般的后台程序证明自己存在的方式就是任务栏的托盘区显示一个图标。于是首先我就按照这个想法先用PyQt5然后在网上找了一段代码然后自己改了改</p>
<h3 id="使用pyqt5库实现">
<a href="#使用pyqt5库实现"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 使用PyQt5库实现
</h3>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">from</span> <span class="nn">PyQt5</span> <span class="kn">import</span> <span class="n">QtCore</span><span class="p">,</span> <span class="n">QtGui</span><span class="p">,</span> <span class="n">QtWidgets</span>
<span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Thread</span>
<span class="k">class</span> <span class="nc">SystemTrayIcon</span><span class="p">(</span><span class="n">QtWidgets</span><span class="p">.</span><span class="n">QSystemTrayIcon</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">icon</span><span class="p">,</span> <span class="n">parent</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="n">QtWidgets</span><span class="p">.</span><span class="n">QSystemTrayIcon</span><span class="p">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">icon</span><span class="p">,</span> <span class="n">parent</span><span class="p">)</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">QtWidgets</span><span class="p">.</span><span class="n">QApplication</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span>
<span class="n">w</span> <span class="o">=</span> <span class="n">QtWidgets</span><span class="p">.</span><span class="n">QWidget</span><span class="p">()</span>
<span class="n">trayIcon</span> <span class="o">=</span> <span class="n">SystemTrayIcon</span><span class="p">(</span><span class="n">QtGui</span><span class="p">.</span><span class="n">QIcon</span><span class="p">(</span><span class="s">"pic.ico"</span><span class="p">),</span> <span class="n">w</span><span class="p">)</span>
<span class="n">trayIcon</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
<span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">some_random_function</span><span class="p">).</span><span class="n">start</span><span class="p">()</span> <span class="c1"># 我的脚本函数
</span><span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="n">app</span><span class="p">.</span><span class="n">exec_</span><span class="p">())</span>
</code></pre></div></div>
<p>这样做完之后东西确实可以运行了不过我的代码还要在其他人的电脑上运行所以我先用Pyinstaller打包了一下不过打包出来的程序很大就几十行代码就算加上Python解析器最多也就不到10MiB结果这加上PyQt库之后直接上升到40MiB左右就算用upx压缩完也有30多MiB实在是让人无法忍受于是我就考虑看看能不能用其他方式来制作这个图标。 </p><p>
后来我在网上找到有一个叫做pystray的库似乎是专门干这个活的。那既然是专门干这个的那大小肯定比什么Qt库要小得多吧于是我按照示例的代码随便写了一段</p>
<h3 id="使用pystray库实现">
<a href="#使用pystray库实现"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 使用pystray库实现
</h3>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Thread</span>
<span class="kn">import</span> <span class="nn">pystray</span>
<span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span>
<span class="n">image</span> <span class="o">=</span> <span class="n">Image</span><span class="p">.</span><span class="nb">open</span><span class="p">(</span><span class="s">"pic.png"</span><span class="p">)</span>
<span class="n">icon</span> <span class="o">=</span> <span class="n">pystray</span><span class="p">.</span><span class="n">Icon</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">"SomeRandom"</span><span class="p">,</span> <span class="n">icon</span><span class="o">=</span><span class="n">image</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s">"SomeRandom"</span><span class="p">,</span> <span class="n">menu</span><span class="o">=</span><span class="bp">None</span><span class="p">)</span>
<span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">some_random_function</span><span class="p">).</span><span class="n">start</span><span class="p">()</span> <span class="c1"># 我的脚本函数
</span><span class="n">icon</span><span class="p">.</span><span class="n">run</span><span class="p">()</span>
</code></pre></div></div>
<p>这个代码我没有测试过不过在我写完之后首先用Pyinstaller打包了一下结果大小比用PyQt5还要大😂打包完大小要60多MiB所以没办法我就只能继续用Qt的那个版本了……</p>
<h2 id="制作悬浮图标">
<a href="#制作悬浮图标"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 制作悬浮图标
</h2>
<p>后来我的脚本由于应用面广泛需要在Ubuntu上使用最新的Ubuntu使用的GNOME桌面<a href="https://blogs.gnome.org/aday/2017/08/31/status-icons-and-gnome/">不再支持托盘区</a>了😓,所以没办法,只能想别的办法了。 </p><p>
现在的程序除了托盘区图标证明自己的存在可能还有就是悬浮球了吧国产很多软件喜欢把自己程序整成悬浮球那样放在桌面上吸引用户的注意力所以我的程序也要这样搞。我想了想用PyQt库实在是太重了我想整个轻量的图形引擎像Python自带的Tkinter就挺不错的所以我首先用Tkinter做了一个版本出来</p>
<h3 id="通过tkinter实现">
<a href="#通过tkinter实现"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 通过Tkinter实现
</h3>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">tkinter</span>
<span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Thread</span>
<span class="n">root</span> <span class="o">=</span> <span class="n">tkinter</span><span class="p">.</span><span class="n">Tk</span><span class="p">()</span>
<span class="n">height</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">width</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">root</span><span class="p">.</span><span class="n">overrideredirect</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
<span class="n">root</span><span class="p">.</span><span class="n">attributes</span><span class="p">(</span><span class="s">'-transparentcolor'</span><span class="p">,</span> <span class="s">"white"</span><span class="p">)</span>
<span class="n">root</span><span class="p">.</span><span class="n">attributes</span><span class="p">(</span><span class="s">"-alpha"</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">)</span> <span class="c1"># 窗口透明度10 %
</span><span class="n">root</span><span class="p">.</span><span class="n">attributes</span><span class="p">(</span><span class="s">"-topmost"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">root</span><span class="p">.</span><span class="n">geometry</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">height</span><span class="si">}</span><span class="s">x</span><span class="si">{</span><span class="n">width</span><span class="si">}</span><span class="s">-40+60"</span><span class="p">)</span>
<span class="n">canvas</span> <span class="o">=</span> <span class="n">tkinter</span><span class="p">.</span><span class="n">Canvas</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="n">height</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="n">width</span><span class="p">,</span> <span class="n">bg</span><span class="o">=</span><span class="s">"white"</span><span class="p">)</span>
<span class="n">canvas</span><span class="p">.</span><span class="n">config</span><span class="p">(</span><span class="n">highlightthickness</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="n">image_file</span> <span class="o">=</span> <span class="n">tkinter</span><span class="p">.</span><span class="n">PhotoImage</span><span class="p">(</span><span class="nb">file</span><span class="o">=</span><span class="sa">r</span><span class="s">'pic.png'</span><span class="p">)</span>
<span class="n">image</span> <span class="o">=</span> <span class="n">canvas</span><span class="p">.</span><span class="n">create_image</span><span class="p">(</span>
<span class="n">height</span><span class="o">//</span><span class="mi">2</span><span class="p">,</span> <span class="n">width</span><span class="o">//</span><span class="mi">2</span><span class="p">,</span> <span class="n">anchor</span><span class="o">=</span><span class="n">tkinter</span><span class="p">.</span><span class="n">CENTER</span><span class="p">,</span> <span class="n">image</span><span class="o">=</span><span class="n">image_file</span><span class="p">)</span>
<span class="n">canvas</span><span class="p">.</span><span class="n">pack</span><span class="p">()</span>
<span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span>
<span class="n">show_menu</span> <span class="o">=</span> <span class="n">tkinter</span><span class="p">.</span><span class="n">Menu</span><span class="p">(</span><span class="n">root</span><span class="p">,</span> <span class="n">tearoff</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="n">show_menu</span><span class="p">.</span><span class="n">add_command</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s">"SomeRandom"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
<span class="k">global</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span>
<span class="n">new_x</span> <span class="o">=</span> <span class="p">(</span><span class="n">event</span><span class="p">.</span><span class="n">x</span><span class="o">-</span><span class="n">x</span><span class="p">)</span><span class="o">+</span><span class="n">root</span><span class="p">.</span><span class="n">winfo_x</span><span class="p">()</span><span class="o">-</span><span class="n">height</span><span class="o">//</span><span class="mi">2</span>
<span class="n">new_y</span> <span class="o">=</span> <span class="p">(</span><span class="n">event</span><span class="p">.</span><span class="n">y</span><span class="o">-</span><span class="n">y</span><span class="p">)</span><span class="o">+</span><span class="n">root</span><span class="p">.</span><span class="n">winfo_y</span><span class="p">()</span><span class="o">-</span><span class="n">width</span><span class="o">//</span><span class="mi">2</span>
<span class="n">s</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">height</span><span class="si">}</span><span class="s">x</span><span class="si">{</span><span class="n">width</span><span class="si">}</span><span class="s">+"</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">new_x</span><span class="p">)</span><span class="o">+</span><span class="s">"+"</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">new_y</span><span class="p">)</span>
<span class="n">root</span><span class="p">.</span><span class="n">geometry</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="n">canvas</span><span class="p">.</span><span class="n">bind</span><span class="p">(</span><span class="s">"&lt;B1-Motion&gt;"</span><span class="p">,</span> <span class="n">move</span><span class="p">)</span>
<span class="n">canvas</span><span class="p">.</span><span class="n">bind</span><span class="p">(</span><span class="s">"&lt;Enter&gt;"</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">event</span><span class="p">:</span> <span class="n">show_menu</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="n">event</span><span class="p">.</span><span class="n">x_root</span><span class="p">,</span> <span class="n">event</span><span class="p">.</span><span class="n">y_root</span><span class="p">))</span>
<span class="n">canvas</span><span class="p">.</span><span class="n">bind</span><span class="p">(</span><span class="s">"&lt;Leave&gt;"</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="n">show_menu</span><span class="p">.</span><span class="n">unpost</span><span class="p">())</span>
<span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">some_random_function</span><span class="p">).</span><span class="n">start</span><span class="p">()</span> <span class="c1"># 我的脚本函数
</span>
<span class="n">root</span><span class="p">.</span><span class="n">mainloop</span><span class="p">()</span>
</code></pre></div></div>
<p>这个代码在Windows上工作还算可以问题不是很多但是在Linux上就出现了很糟糕的问题根据tcl/tk <a href="https://wiki.tcl-lang.org/page/wm+attributes">documentation</a> <del>好像也没写🤣</del> ,“-transparentcolor”属性只能在Windows等系统使用貌似MacOS也能用因此在Linux中会报错。如果不能使用透明背景效果就会很差我看Stack Overflow上有人说可以安装一个pqiv图片查看器然后使用<code class="language-plaintext highlighter-rouge">os.popen()</code>或者<code class="language-plaintext highlighter-rouge">subprocess.Popen()</code>执行<code class="language-plaintext highlighter-rouge">pqiv -c -c -i pic.png</code>也能达到类似的效果不过这种东西先不说还要安装而且这个东西点两下就能看见它的窗口还能关闭那肯定是不符合我们的要求的。所以没办法……只能再考虑Qt的办法了。</p>
<h3 id="使用pyqt5库实现-1">
<a href="#使用pyqt5库实现-1"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 使用PyQt5库实现
</h3>
<p>我在网上又找了些资料把PyQt的版本也做出来了而且还加了支持Gif动态图片的效果</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">from</span> <span class="nn">PyQt5.QtWidgets</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">PyQt5.QtGui</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">PyQt5.QtCore</span> <span class="kn">import</span> <span class="o">*</span>
<span class="k">class</span> <span class="nc">Example</span><span class="p">(</span><span class="n">QWidget</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">()</span>
<span class="bp">self</span><span class="p">.</span><span class="n">initUI</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">mouseMoveEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="n">QMouseEvent</span><span class="p">):</span> <span class="c1"># 重写移动事件
</span> <span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">_tracking</span><span class="p">:</span>
<span class="bp">self</span><span class="p">.</span><span class="n">_endPos</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">pos</span><span class="p">()</span> <span class="o">-</span> <span class="bp">self</span><span class="p">.</span><span class="n">_startPos</span>
<span class="bp">self</span><span class="p">.</span><span class="n">move</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">pos</span><span class="p">()</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">_endPos</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">mousePressEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="n">QMouseEvent</span><span class="p">):</span>
<span class="k">if</span> <span class="n">e</span><span class="p">.</span><span class="n">button</span><span class="p">()</span> <span class="o">==</span> <span class="n">Qt</span><span class="p">.</span><span class="n">LeftButton</span><span class="p">:</span>
<span class="bp">self</span><span class="p">.</span><span class="n">_startPos</span> <span class="o">=</span> <span class="n">QPoint</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">x</span><span class="p">(),</span> <span class="n">e</span><span class="p">.</span><span class="n">y</span><span class="p">())</span>
<span class="bp">self</span><span class="p">.</span><span class="n">_tracking</span> <span class="o">=</span> <span class="bp">True</span>
<span class="k">def</span> <span class="nf">mouseReleaseEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="n">QMouseEvent</span><span class="p">):</span>
<span class="k">if</span> <span class="n">e</span><span class="p">.</span><span class="n">button</span><span class="p">()</span> <span class="o">==</span> <span class="n">Qt</span><span class="p">.</span><span class="n">LeftButton</span><span class="p">:</span>
<span class="bp">self</span><span class="p">.</span><span class="n">_tracking</span> <span class="o">=</span> <span class="bp">False</span>
<span class="bp">self</span><span class="p">.</span><span class="n">_startPos</span> <span class="o">=</span> <span class="bp">None</span>
<span class="bp">self</span><span class="p">.</span><span class="n">_endPos</span> <span class="o">=</span> <span class="bp">None</span>
<span class="k">def</span> <span class="nf">initUI</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">layout</span> <span class="o">=</span> <span class="n">QStackedLayout</span><span class="p">()</span>
<span class="bp">self</span><span class="p">.</span><span class="n">lbl1</span> <span class="o">=</span> <span class="n">QLabel</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">movie</span> <span class="o">=</span> <span class="n">QMovie</span><span class="p">(</span><span class="s">"pic.gif"</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">lbl1</span><span class="p">.</span><span class="n">setMovie</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">movie</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">movie</span><span class="p">.</span><span class="n">start</span><span class="p">()</span>
<span class="bp">self</span><span class="p">.</span><span class="n">lbl1</span><span class="p">.</span><span class="n">setToolTip</span><span class="p">(</span><span class="s">"SomeRandom"</span><span class="p">)</span>
<span class="n">layout</span><span class="p">.</span><span class="n">addWidget</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">lbl1</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">setAttribute</span><span class="p">(</span><span class="n">Qt</span><span class="p">.</span><span class="n">WA_TranslucentBackground</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">setWindowFlags</span><span class="p">(</span><span class="n">Qt</span><span class="p">.</span><span class="n">WindowStaysOnTopHint</span> <span class="o">|</span> <span class="n">Qt</span><span class="p">.</span><span class="n">FramelessWindowHint</span> <span class="o">|</span> <span class="n">Qt</span><span class="p">.</span><span class="n">Tool</span><span class="p">)</span>
<span class="c1">#layout area for widgets
</span> <span class="n">layout</span><span class="p">.</span><span class="n">setCurrentIndex</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">setLayout</span><span class="p">(</span><span class="n">layout</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">setGeometry</span><span class="p">(</span><span class="n">QApplication</span><span class="p">.</span><span class="n">desktop</span><span class="p">().</span><span class="n">width</span><span class="p">()</span><span class="o">-</span><span class="mi">130</span><span class="p">,</span><span class="mi">50</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">100</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">QApplication</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span>
<span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">some_random_function</span><span class="p">).</span><span class="n">start</span><span class="p">()</span> <span class="c1"># 我的脚本函数
</span> <span class="n">ex</span> <span class="o">=</span> <span class="n">Example</span><span class="p">()</span>
<span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="n">app</span><span class="p">.</span><span class="n">exec_</span><span class="p">())</span>
</code></pre></div></div>
<p>最终做出来效果还不错说不定加点功能放组简单的立绘动画就能做一个像我博客左下角的看板娘一样的东西呢🤣虽然我也见过用Electron写的<a href="https://github.com/zenghongtu/PPet">PPet</a>不过用Python写的话可能对更多人更友好吧 <del>Gif哪能和Live2D比😂</del></p>
<h1 id="感想">
<a href="#感想"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 感想
</h1>
<p>这次做这么一个Python程序运行的提示标志还真是复杂啊尤其是为了跨平台其实专门对应一个平台做起来可能也没有很复杂不过想能在各个平台上都能使用还是挺难的。这次来看Qt的跨平台性确实很强无论是在哪个平台上都能获得不错的体验就是用起来感觉比较麻烦其实说来如果能用C++之类的语言去开发Qt程序应该更好Python这个基本上也就只能当作一个玩具算是熟悉一下Qt的各种功能了。</p></main>
<small style="display: block">tags: <a rel="category tag" class="p-category" href="/search.html?keyword=Python"><em>Python</em></a> - <a rel="category tag" class="p-category" href="/search.html?keyword=%E7%A8%8B%E5%BA%8F"><em>程序</em></a> - <a rel="category tag" class="p-category" href="/search.html?keyword=%E6%A0%87%E5%BF%97"><em>标志</em></a> <span style="float: right;"><a href="https://gitlab.com/mayx/mayx.gitlab.io/tree/master/_posts/2022-09-05-trayicon.md">查看原始文件</a></span></small>
<h4 style="border-bottom: 1px solid #e5e5e5;margin: 2em 0 5px;">推荐文章</h4>
<p id="suggest-container">Loading...</p>
<script>
var suggest = $("#suggest-container");
$.get(BlogAPI + "/suggest?id=/2022/09/05/trayicon.html&update=" + lastUpdated.valueOf(), function (data) {
if (data.length) {
getSearchJSON(function (search) {
suggest.empty();
var searchMap = {};
for (var i = 0; i < search.length; i++) {
searchMap[search[i].url] = search[i];
}
var tooltip = $('<div class="content-tooltip"></div>').appendTo('body').hide();
for (var j = 0; j < data.length; j++) {
var item = searchMap[data[j].id];
if (item) {
var link = $('<a href="' + item.url + '">' + item.title + '</a>');
var contentPreview = item.content.substring(0, 100);
if (item.content.length > 100) {
contentPreview += "……";
}
link.hover(
function(e) {
tooltip.text($(this).data('content'))
.css({
top: e.pageY + 10,
left: e.pageX + 10
})
.show();
},
function() {
tooltip.hide();
}
).mousemove(function(e) {
tooltip.css({
top: e.pageY + 10,
left: e.pageX + 10
});
}).data('content', contentPreview);
suggest.append(link);
suggest.append(' - ' + item.date + '<br />');
}
}
});
} else {
suggest.html("暂无推荐文章……");
}
});
</script>
<br />
<div class="pagination">
<span class="prev">
<a href="/2022/08/15/cdn-verify.html">
上一篇如何避免Cloudflare背后的源站被恶意访问
</a>
</span>
<br />
<span class="next">
<a href="/2022/09/21/cron.html">
下一篇使用Python制作可热载的定时调度器
</a>
</span>
</div>
<!--[if !IE]> -->
<link rel="stylesheet" href="/assets/css/gitalk.css">
<script src="/assets/js/gitalk.min.js"></script>
<div id="gitalk-container"></div>
<script>
var gitalk = new Gitalk({
clientID: '36557aec4c3cb04f7ac6',
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
repo: 'mabbs.github.io',
owner: 'Mabbs',
admin: ['Mabbs'],
id: '/2022/09/05/trayicon', // Ensure uniqueness and length less than 50
distractionFreeMode: false, // Facebook-like distraction free mode
proxy: "https://cors-anywhere.mayx.eu.org/?https://github.com/login/oauth/access_token"
})
gitalk.render('gitalk-container')
</script>
<!-- <![endif]-->
</section>
<!--[if !IE]> -->
<div id="landlord" style="left:5px;bottom:0px;">
<div class="message" style="opacity:0"></div>
<canvas id="live2d" width="500" height="560" class="live2d"></canvas>
<div class="live_talk_input_body">
<form id="live_talk_input_form">
<div class="live_talk_input_name_body" >
<input type="checkbox" id="load_this" />
<input type="hidden" id="post_id" value="/2022/09/05/trayicon.html" />
<label for="load_this">
<span style="font-size: 11px; color: #fff;">&#160;想问这篇文章</span>
</label>
</div>
<div class="live_talk_input_text_body">
<input name="talk" type="text" class="live_talk_talk white_input" id="AIuserText" autocomplete="off" placeholder="要和我聊什么呀?" />
<button type="submit" class="live_talk_send_btn" id="talk_send">发送</button>
</div>
</form>
</div>
<input name="live_talk" id="live_talk" value="1" type="hidden" />
<div class="live_ico_box" style="display:none;">
<div class="live_ico_item type_info" id="showInfoBtn"></div>
<div class="live_ico_item type_talk" id="showTalkBtn"></div>
<div class="live_ico_item type_music" id="musicButton"></div>
<div class="live_ico_item type_youdu" id="youduButton"></div>
<div class="live_ico_item type_quit" id="hideButton"></div>
<input name="live_statu_val" id="live_statu_val" value="0" type="hidden" />
<audio src="" style="display:none;" id="live2d_bgm" data-bgm="0" preload="none"></audio>
<input id="duType" value="douqilai" type="hidden" />
</div>
</div>
<div id="open_live2d">召唤伊斯特瓦尔</div>
<!-- <![endif]-->
<footer>
<p>
<small>Made with ❤ by Mayx<br />Last updated at 2026-01-01 00:00:18<br /> 总字数614622 - 文章数178 - <a href="/atom.xml" >Atom</a> - <a href="/README.html" >About</a></small>
</p>
</footer>
</div>
<script src="/assets/js/scale.fix.js"></script>
<!--[if !IE]> -->
<script src="/assets/js/main_new.js"></script>
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
<script src="/Live2dHistoire/live2d/js/message.js"></script>
<!-- <![endif]-->
</body>
</html>