{"id":10258,"date":"2023-06-06T14:18:42","date_gmt":"2023-06-06T06:18:42","guid":{"rendered":"https:\/\/blog.iyatt.com\/?p=10258"},"modified":"2024-05-05T12:32:22","modified_gmt":"2024-05-05T04:32:22","slug":"%e5%9f%ba%e4%ba%8e-python-tkinter-%e7%9a%84%e8%ae%b0%e4%ba%8b%e6%9c%ac-demo","status":"publish","type":"post","link":"https:\/\/blog.iyatt.com\/?p=10258","title":{"rendered":"Python Tkinter \u5b66\u4e60 demo"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 ez-toc-wrap-center counter-hierarchy ez-toc-counter ez-toc-light-blue ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title ez-toc-toggle\" style=\"cursor:pointer\">\u76ee\u5f55<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E5%89%8D%E8%A8%80\" >\u524d\u8a00<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E7%8E%AF%E5%A2%83\" >\u73af\u5883<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E4%BB%A3%E7%A0%81\" >\u4ee3\u7801<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E6%A1%86%E6%9E%B6%EF%BC%88Pack_%E5%B8%83%E5%B1%80%EF%BC%89\" >\u6846\u67b6\uff08Pack \u5e03\u5c40\uff09<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E9%80%89%E7%89%8C%EF%BC%88place_%E5%B8%83%E5%B1%80%EF%BC%89\" >\u9009\u724c\uff08place \u5e03\u5c40\uff09<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E7%99%BB%E5%BD%95%E7%95%8C%E9%9D%A2%E8%AE%A1%E7%AE%97%E5%99%A8%EF%BC%88Grid_%E5%B8%83%E5%B1%80%EF%BC%89\" >\u767b\u5f55\u754c\u9762+\u8ba1\u7b97\u5668\uff08Grid \u5e03\u5c40\uff09<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E9%80%89%E9%A1%B9%E8%8F%9C%E5%8D%95\" >\u9009\u9879\u83dc\u5355<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E6%BB%91%E5%9D%97\" >\u6ed1\u5757<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E8%AE%B0%E4%BA%8B%E6%9C%AC\" >\u8bb0\u4e8b\u672c<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E7%AE%80%E6%98%93%E5%9B%BE%E7%89%87%E6%9F%A5%E7%9C%8B%E5%99%A8\" >\u7b80\u6613\u56fe\u7247\u67e5\u770b\u5668<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/blog.iyatt.com\/?p=10258\/#%E6%91%84%E5%83%8F%E5%A4%B4%E9%A2%84%E8%A7%88\" >\u6444\u50cf\u5934\u9884\u89c8<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"%E5%89%8D%E8%A8%80\"><\/span>\u524d\u8a00<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>\u8fd9\u4e9b\u4e3b\u8981\u662f 21 \u5e74\u7684\u65f6\u5019\u5b66\u4e60 Python \u7684\u5b98\u65b9\u56fe\u5f62\u5e93 Tkinter \u65f6\u5199\u7684\uff0c\u5728\u5199\u6bd4\u8f83\u7b80\u5355\u7684\u5de5\u5177\u7684\u65f6\u5019\u7528\u8fd9\u4e2a\u5e93\u4f1a\u6bd4\u8f83\u65b9\u4fbf\uff0c\u4e5f\u4e0d\u4f9d\u8d56\u7b2c\u4e09\u65b9\uff0c\u8fd9\u4e9b demo \u7b97\u662f tk \u7684\u7b80\u5355\u5e94\u7528\uff0c\u5bf9\u4e8e\u6709\u9700\u8981\u7684\u53ef\u4ee5\u7528\u4f5c\u53c2\u8003\u3002<\/p>\n<h2><span class=\"ez-toc-section\" id=\"%E7%8E%AF%E5%A2%83\"><\/span>\u73af\u5883<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>\u7f16\u5199\u65f6\u7684\u6d4b\u8bd5\u73af\u5883\uff1aPython 3.8.11<br \/>\n\u672c\u6587\u518d\u6b21\u9a8c\u8bc1\u7684\u73af\u5883\uff1a<br \/>\nUbuntu 22.04\uff08Windows 11 \u4e13\u4e1a\u5de5\u4f5c\u7ad9\u7248 22H2 WSL2\uff09<br \/>\nPython 3.11.3<\/p>\n<p>\u6e90\u7801\u6ce8\u660e\u7684\u9664\u5916<\/p>\n<h2><span class=\"ez-toc-section\" id=\"%E4%BB%A3%E7%A0%81\"><\/span>\u4ee3\u7801<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"%E6%A1%86%E6%9E%B6%EF%BC%88Pack_%E5%B8%83%E5%B1%80%EF%BC%89\"><\/span>\u6846\u67b6\uff08Pack \u5e03\u5c40\uff09<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre><code class=\"language-python\">&quot;&quot;&quot;\n@brief Tkinter \u9762\u5411\u5bf9\u8c61\u8bbe\u8ba1\u6846\u67b6\n\nCopyright (C) 2021 IYATT-yx iyatt@iyatt.com\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\nThis program is free software: you can redistribute it and\/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see &lt;https:\/\/www.gnu.org\/licenses\/&gt;.\n&quot;&quot;&quot;\nfrom tkinter import *\nimport tkinter.messagebox as messagebox\nimport tkinter.font as font\n\nclass Application(Frame):\n    def __init__(self, master=None):\n        super().__init__(master)  # \u7236\u7c7b\n        self.__master = master\n        self.pack()\n\n        self.createWidget()\n\n    def createWidget(self):\n        # \u6807\u7b7e\u7ec4\u4ef6\n        self.label = Label(\n            self, text=&#039;\u8fd9\u662f\u4e00\u4e2a\u6807\u7b7e&#039;, width=10, height=1, bg=&#039;red&#039;, fg=&#039;black&#039;\n        )\n        self.label.pack()\n\n        # \u6309\u94ae\u7ec4\u4ef6\n        self.btn1 = Button(self)\n        self.btn1[&#039;text&#039;] = &#039;\u6309\u94ae&#039;\n        self.btn1[&#039;command&#039;] = self.doWork\n        self.btn1[&#039;anchor&#039;] = NE  # \u6587\u5b57\u5728\u6309\u94ae\u4e2d\u7684\u4f4d\u7f6e north east\n        self.btn1.config(width=5, height=5)\n        self.btn1.pack()\n\n        # \u5355\u884c\u8f93\u5165\u6846\n        self.entryVar = StringVar(value=&#039;hello&#039;)\n        self.entry = Entry(self, textvariable=self.entryVar)\n        self.entry.pack()\n\n        self.btn2 = Button(self, text=&#039;\u67e5\u770b\u5355\u884c\u6846&#039;, command=self.viewEntry)\n        self.btn2.pack()\n\n        # \u591a\u884c\u8f93\u5165\u6846\n        self.text = Text(self, width=40, height=5, bg=&#039;blue&#039;)\n        self.text.pack()\n\n        self.btn3 = Button(self, text=&#039;\u67e5\u770b\u591a\u884c\u6846&#039;, command=self.viewText)\n        self.btn3.pack()\n\n        # \u5355\u9009\u6846\n        self.radioVar = StringVar()\n        self.radioVar.set(&#039;\u5355\u9009\u4e00&#039;)  # \u9ed8\u8ba4\u521d\u59cb\u9009\u4e2d\n        self.radio1 = Radiobutton(self, text=&#039;\u5355\u9009\u4e00&#039;, value=&#039;\u5355\u9009\u4e00&#039;, variable=self.radioVar)\n        self.radio2 = Radiobutton(self, text=&#039;\u5355\u9009\u4e8c&#039;, value=&#039;\u5355\u9009\u4e8c&#039;, variable=self.radioVar)\n        self.radio1.pack(side=&#039;left&#039;)\n        self.radio2.pack(side=&#039;left&#039;)\n\n        # \u591a\u9009\u6846\n        self.checkVar1 = IntVar()\n        self.checkVar2 = IntVar()\n        self.check1 = Checkbutton(\n            self, text=&#039;\u9009\u9879\u4e00&#039;, variable=self.checkVar1, onvalue=1, offvalue=0\n        )\n        self.check2 = Checkbutton(\n            self, text=&#039;\u9009\u9879\u4e8c&#039;, variable=self.checkVar2, onvalue=1, offvalue=0\n        )\n        self.check1.pack(side=&#039;right&#039;)\n        self.check2.pack(side=&#039;right&#039;)\n\n        # \u753b\u5e03\n        self.canvas = Canvas(self, width=100, height=100, bg=&#039;green&#039;)\n        self.canvas.pack()\n        self.canvas.create_line(10, 10, 30, 30, 50, 50, 70, 10, 90, 90)\n        self.canvas.create_rectangle(20, 20, 80, 90)\n\n        # \u9000\u51fa\u6309\u94ae\n        self.btnQuit = Button(self, text=&#039;\u9000\u51fa&#039;, command=self.__master.destroy)\n        self.btnQuit.pack()\n\n    def doWork(self):\n        messagebox.showinfo(&#039;\u63d0\u793a&#039;, &#039;\u6309\u94ae\u88ab\u70b9\u51fb&#039;)\n\n    # \u67e5\u770b\u4f60\u5355\u884c\u8f93\u5165\u6846\u7684\u503c\n    def viewEntry(self):\n        self.text.insert(INSERT, self.entryVar.get())\n        # messagebox.showinfo(&#039;\u67e5\u770b\u5355\u884c\u6846&#039;, self.entryVar.get())\n        messagebox.showinfo(&#039;\u67e5\u770b\u5355\u884c\u6846&#039;, self.entry.get())\n\n    def viewText(self):\n        messagebox.showinfo(&#039;\u67e5\u770b\u591a\u884c\u6846&#039;, self.text.get(1.0, END))\n\nif __name__ == &#039;__main__&#039;:\n    root = Tk()\n    root.geometry(&#039;400x500+300+200&#039;)  # 400x200 \u5de6\u8ddd300 \u4e0a\u8ddd200\n    defaultFont = font.Font(family=&#039;\u9ed1\u4f53&#039;, size=12)  # \u5b57\u4f53\n    root.option_add(&quot;*Font&quot;, defaultFont)\n    root.title(&#039;Tkinter \u9762\u5411\u5bf9\u8c61\u8bbe\u8ba1\u6846\u67b6\u793a\u4f8b&#039;)\n    app = Application(master=root)\n\n    root.mainloop()<\/code><\/pre>\n<p><img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686068044036.png\" alt=\"\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 683px; --smush-placeholder-aspect-ratio: 683\/556;\" \/><\/p>\n<h3><span class=\"ez-toc-section\" id=\"%E9%80%89%E7%89%8C%EF%BC%88place_%E5%B8%83%E5%B1%80%EF%BC%89\"><\/span>\u9009\u724c\uff08place \u5e03\u5c40\uff09<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>\u56fe\u50cf\u8d44\u6e90\u4e0b\u8f7d\uff1a<a href=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/resources.zip\" title=\"resources\">resources<\/a><br \/>\n\u6587\u4ef6\u4e0b\u8f7d\u89e3\u538b\u540e\u5f97\u5230\u7684\u6587\u4ef6\u5939\u653e\u5230\u6e90\u7801\u6240\u5728\u7684\u76ee\u5f55\u4e0b<\/p>\n<pre><code class=\"language-python\">#!\/usr\/bin\/env python3\n&quot;&quot;&quot;\n@brief \u9009\u724c\n\nCopyright (C) 2021 IYATT-yx iyatt@iyatt.com\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\nThis program is free software: you can redistribute it and\/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see &lt;https:\/\/www.gnu.org\/licenses\/&gt;.\n&quot;&quot;&quot;\nfrom tkinter import *\nimport os\n\nclass Application(Frame):\n    def __init__(self, master=None):\n        super().__init__(master)\n        self.__master = master\n        self.pack()\n\n    def createWidgets(self):\n        abspath = os.path.dirname(os.path.abspath(__file__))\n\n        self.photo = [\n            PhotoImage(file=abspath + &#039;\/resources\/&#039; + str(i) + &#039;.png&#039;) for i in range(9)\n        ]\n        self.label = [Label(self.__master, image=self.photo[i]) for i in range(9)]\n\n        for i in range(0, 9):\n            self.label[i].place(x=30 + i * 30, y=120)\n\n        self.label[0].bind_class(&#039;Label&#039;, &#039;&lt;Button-1&gt;&#039;, self.play)\n\n    # \u9009\u724c\n    def play(self, event):\n        if event.widget.winfo_y() == 120:\n            event.widget.place(y=90)\n        else:\n            event.widget.place(y=120)\n\nif __name__ == &#039;__main__&#039;:\n    root = Tk()\n    root.geometry(&#039;400x400+400+400&#039;)\n    root.title(&#039;\u9009\u724c&#039;)\n    app = Application(root)\n    app.createWidgets()\n    root.mainloop()<\/code><\/pre>\n<p>\u70b9\u51fb\u9009\u724c<br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686056357699.png\" alt=\"\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 402px; --smush-placeholder-aspect-ratio: 402\/437;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686056383560.png\" alt=\"\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 411px; --smush-placeholder-aspect-ratio: 411\/350;\" \/><\/p>\n<h3><span class=\"ez-toc-section\" id=\"%E7%99%BB%E5%BD%95%E7%95%8C%E9%9D%A2%E8%AE%A1%E7%AE%97%E5%99%A8%EF%BC%88Grid_%E5%B8%83%E5%B1%80%EF%BC%89\"><\/span>\u767b\u5f55\u754c\u9762+\u8ba1\u7b97\u5668\uff08Grid \u5e03\u5c40\uff09<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre><code class=\"language-python\">&quot;&quot;&quot;\n@brief \u767b\u5f55\u754c\u9762+\u8ba1\u7b97\u5668\n\nCopyright (C) 2021 IYATT-yx iyatt@iyatt.com\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\nThis program is free software: you can redistribute it and\/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see &lt;https:\/\/www.gnu.org\/licenses\/&gt;.\n&quot;&quot;&quot;\nfrom tkinter import *\n\nclass GridApplication(Frame):\n    def __init__(self, master=None):\n        super().__init__(master)\n        self.__master = master\n        self.pack()\n\n    def createWidget(self):\n        Label(self, text=&#039;\u7528\u6237\u540d&#039;).grid(column=0, row=0)\n        self.entry1 = Entry(self)\n        self.entry1.grid(column=1, row=0)\n\n        Label(self, text=&#039;\u5bc6\u7801&#039;).grid(column=0, row=1)\n        self.entry2 = Entry(self, show=&#039;*&#039;)\n        self.entry2.grid(column=1, row=1)\n\n        Button(self, text=&#039;\u767b\u5f55&#039;).grid(column=1, row=2, sticky=EW)\n        Button(self, text=&#039;\u9000\u51fa&#039;, command=self.__master.destroy).grid(\n            column=2, row=2, sticky=E\n        )\n\n# \u8ba1\u7b97\u5668\u5e03\u5c40\nclass Calculator(Frame):\n    def __init__(self, master=None):\n        super().__init__(master)\n        self.__master = master\n        self.pack()\n\n    def createWidget(self):\n        # \u8ba1\u7b97\u5f0f\u663e\u793a\u6846\n        Text(self, height=3).grid(column=0, row=0, columnspan=4, sticky=EW)\n        Button(self, text=&#039;7&#039;).grid(column=0, row=1, sticky=EW)\n        Button(self, text=&#039;8&#039;).grid(column=1, row=1, sticky=EW)\n        Button(self, text=&#039;9&#039;).grid(column=2, row=1, sticky=EW)\n        Button(self, text=&#039;\u00f7&#039;).grid(column=3, row=1, sticky=EW)\n        Button(self, text=&#039;4&#039;).grid(column=0, row=2, sticky=EW)\n        Button(self, text=&#039;5&#039;).grid(column=1, row=2, sticky=EW)\n        Button(self, text=&#039;6&#039;).grid(column=2, row=2, sticky=EW)\n        Button(self, text=&#039;\u00d7&#039;).grid(column=3, row=2, sticky=EW)\n        Button(self, text=&#039;1&#039;).grid(column=0, row=3, sticky=EW)\n        Button(self, text=&#039;2&#039;).grid(column=1, row=3, sticky=EW)\n        Button(self, text=&#039;3&#039;).grid(column=2, row=3, sticky=EW)\n        Button(self, text=&#039;-&#039;).grid(column=3, row=3, sticky=EW)\n        Button(self, text=&#039;0&#039;).grid(column=0, row=4, sticky=EW)\n        Button(self, text=&#039;.&#039;).grid(column=1, row=4, sticky=EW)\n        Button(self, text=&#039;=&#039;).grid(column=2, row=4, sticky=EW)\n        Button(self, text=&#039;+&#039;).grid(column=3, row=4, sticky=EW)\n\nif __name__ == &#039;__main__&#039;:\n    grid = Tk()\n    grid.geometry(&#039;300x100+300+400&#039;)\n    grid.title(&#039;grid\u5e03\u5c40\u6f14\u793a&#039;)\n    gridApp = GridApplication(grid)\n    gridApp.createWidget()\n\n    calc = Tk()\n    calc.geometry(&#039;700x200+700+400&#039;)\n    calc.title(&#039;\u8ba1\u7b97\u5668\u5e03\u5c40&#039;)\n    calcApp = Calculator(calc)\n    calcApp.createWidget()\n\n    mainloop()<\/code><\/pre>\n<p><img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686068678669.png\" alt=\"\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 721px; --smush-placeholder-aspect-ratio: 721\/383;\" \/><\/p>\n<h3><span class=\"ez-toc-section\" id=\"%E9%80%89%E9%A1%B9%E8%8F%9C%E5%8D%95\"><\/span>\u9009\u9879\u83dc\u5355<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre><code class=\"language-python\">#!\/usr\/bin\/env python3\n&quot;&quot;&quot;\n@brief \u9009\u9879\u83dc\u5355\n\nCopyright (C) 2021 IYATT-yx iyatt@iyatt.com\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\nThis program is free software: you can redistribute it and\/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see &lt;https:\/\/www.gnu.org\/licenses\/&gt;.\n&quot;&quot;&quot;\nfrom tkinter import *\n\nclass Application(Frame):\n    def __init__(self, master=None):\n        super().__init__(master)\n        self.__master = master\n        self.pack()\n\n    def createWidgets(self):\n        var = StringVar()\n        var.set(&#039;\u7b2c\u4e00\u4e2a\u9009\u9879&#039;)\n        self.__om = OptionMenu(self.__master, var, &#039;\u7b2c\u4e00\u4e2a\u9009\u9879&#039;, &#039;\u7b2c\u4e8c\u4e2a\u9009\u9879&#039;, &#039;\u7b2c\u4e09\u4e2a\u9009\u9879&#039;)\n        self.__om[&#039;width&#039;] = 50\n        self.__om.pack()\n\nif __name__ == &#039;__main__&#039;:\n    root = Tk()\n    root.geometry(&#039;300x100+400+400&#039;)\n    root.title(&#039;\u9009\u9879\u83dc\u5355&#039;)\n    app = Application(root)\n    app.createWidgets()\n    root.mainloop()<\/code><\/pre>\n<p><img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686057095240.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 327px; --smush-placeholder-aspect-ratio: 327\/148;\" \/><\/p>\n<h3><span class=\"ez-toc-section\" id=\"%E6%BB%91%E5%9D%97\"><\/span>\u6ed1\u5757<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre><code class=\"language-python\">#!\/usr\/bin\/env python3\n&quot;&quot;&quot;\n@brief \u6ed1\u5757\n\nCopyright (C) 2021 IYATT-yx iyatt@iyatt.com\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\nThis program is free software: you can redistribute it and\/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see &lt;https:\/\/www.gnu.org\/licenses\/&gt;.\n&quot;&quot;&quot;\nfrom tkinter import *\n\nclass Application(Frame):\n    def __init__(self, master=None):\n        super().__init__(master)\n        self.__master = master\n        self.pack()\n\n    def showVar(self, value):\n        print(&#039;\u6ed1\u5757\u503c\uff1a&#039;, value)\n\n    def createWidgets(self):\n        Scale(\n            self.__master,\n            from_=0,\n            to=50,\n            length=500,\n            tickinterval=5,\n            orient=HORIZONTAL,\n            command=self.showVar,\n        ).pack()\n\nif __name__ == &#039;__main__&#039;:\n    root = Tk()\n    root.geometry(&#039;600x100+400+400&#039;)\n    root.title(&#039;\u6ed1\u5757&#039;)\n    app = Application(root)\n    app.createWidgets()\n    root.mainloop()<\/code><\/pre>\n<p><img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686057176601.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 765px; --smush-placeholder-aspect-ratio: 765\/259;\" \/><\/p>\n<h3><span class=\"ez-toc-section\" id=\"%E8%AE%B0%E4%BA%8B%E6%9C%AC\"><\/span>\u8bb0\u4e8b\u672c<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre><code class=\"language-python\">&quot;&quot;&quot;\n@brief \u8bb0\u4e8b\u672c\n\nCopyright (C) 2021 IYATT-yx iyatt@iyatt.com\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\nThis program is free software: you can redistribute it and\/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see &lt;https:\/\/www.gnu.org\/licenses\/&gt;.\n&quot;&quot;&quot;\nfrom tkinter import *\nfrom tkinter.filedialog import *\nfrom tkinter.messagebox import *\nfrom tkinter.colorchooser import *\nimport os\n\nclass Notepad(Frame):\n    def __init__(self, master=None):\n        super().__init__(master)\n        self.__master = master\n        self.pack()\n        self.__saveType = &#039;newFile&#039;\n        self.__master.protocol(&quot;WM_DELETE_WINDOW&quot;, self.__onClosing)\n\n    def createWidgets(self):\n        &quot;&quot;&quot; \u4e0b\u62c9\u83dc\u5355\n        &quot;&quot;&quot;\n\n        # \u4e3b\u83dc\u5355\u680f\n        self.__menubar = Menu(self.__master)\n        self.__master.config(menu=self.__menubar)\n\n        # \u6587\u4ef6\n        self.__fileMenu = Menu(self.__menubar)\n        self.__menubar.add_cascade(label=&#039;\u6587\u4ef6&#039;, menu=self.__fileMenu)\n        # \u8bbe\u7f6e\n        self.__setMenu = Menu(self.__master)\n        self.__menubar.add_cascade(label=&#039;\u8bbe\u7f6e&#039;, menu=self.__setMenu)\n        # \u5e2e\u52a9\n        self.__aboutMenu = Menu(self.__master)\n        self.__menubar.add_cascade(label=&#039;\u5e2e\u52a9&#039;, menu=self.__aboutMenu)\n\n        # \u6587\u4ef6 - \u5b50\u9009\u9879\n        self.__fileMenu.add_command(label=&#039;\u65b0\u5efa&#039;, command=self.__newFile)\n        self.__fileMenu.add_command(label=&#039;\u6253\u5f00&#039;, command=self.__openFile)\n        self.__fileMenu.add_command(label=&#039;\u4fdd\u5b58&#039;, command=self.__saveFile)\n        self.__fileMenu.add_command(label=&#039;\u53e6\u5b58\u4e3a&#039;, command=self.__saveAs)\n        # \u8bbe\u7f6e - \u5b50\u9009\u9879\n        self.__setMenu.add_command(label=&#039;\u80cc\u666f\u989c\u8272&#039;, command=self.__setBg)\n        # \u5e2e\u52a9 - \u5b50\u9009\u9879\n        self.__aboutMenu.add_command(label=&#039;\u5173\u4e8e&#039;, command=self.__about)\n\n        # \u6587\u672c\u6846\n        self.__text = Text()\n        self.__text.place(relx=0.001, rely=0.001, relwidth=0.998, relheight=0.998)\n\n        # \u6587\u672c\u6846\u5185\u5bb9\u4fee\u6539\u4e8b\u4ef6\u54cd\u5e94\n        self.__isChanged = False\n        self.__text.bind(&#039;&lt;KeyPress&gt;&#039;, self.__changeFlag)\n\n    def __newFile(self):\n        &quot;&quot;&quot; \u65b0\u5efa\u6587\u4ef6\n        &quot;&quot;&quot;\n        self.__saveType = &#039;newFile&#039;\n\n        if self.__isChanged == True:\n            if askyesnocancel(title=&#039;\u63d0\u793a&#039;, message=&#039;\u662f\u5426\u4fdd\u5b58\uff1f&#039;):\n                self.__saveFile()\n            else:\n                return\n\n        self.__text.delete(1.0, END)\n\n    def __openFile(self):\n        &quot;&quot;&quot; \u6253\u5f00\u6587\u4ef6\n        &quot;&quot;&quot;\n        self.__saveType = &#039;openFile&#039;\n\n        if self.__isChanged == True:\n            if self.__isChanged == True:\n                confirm = askyesnocancel(title=&#039;\u63d0\u793a&#039;, message=&#039;\u662f\u5426\u4fdd\u5b58\uff1f&#039;)\n                if confirm == True:\n                    self.__saveFile()\n                elif confirm == None:\n                    return\n                else:\n                    pass\n\n        self.__fileName = askopenfilename(title=&#039;\u6253\u5f00\u6587\u4ef6&#039;)\n\n        if not self.__fileName:\n            return\n\n        with open(self.__fileName, &#039;r&#039;) as f:\n            self.__text.delete(1.0, END)\n            self.__text.insert(INSERT, f.read())\n\n        self.__isChanged = False\n\n    def __saveFile(self):\n        &quot;&quot;&quot; \u4fdd\u5b58\u6587\u4ef6\n        &quot;&quot;&quot;\n        if self.__saveType == &#039;newFile&#039; or self.__saveType == &#039;saveAs&#039;:\n            self.__fileName = asksaveasfilename(\n                title=&#039;\u65b0\u5efa\u6587\u4ef6&#039;,\n                initialfile=&#039;\u672a\u547d\u540d.txt&#039;,\n                filetypes=[(&#039;\u6587\u672c\u6587\u6863&#039;, &#039;*.txt&#039;)],\n                defaultextension=&#039;*.txt&#039;,\n            )\n        elif self.__saveType == &#039;openFile&#039;:\n            pass\n\n        if not self.__fileName:\n            return\n\n        with open(self.__fileName, &#039;w&#039;) as f:\n            f.write(self.__text.get(1.0, END))\n\n        self.__isChanged = False\n\n    def __saveAs(self):\n        &quot;&quot;&quot; \u53e6\u5b58\u4e3a\n        &quot;&quot;&quot;\n        self.__saveType = &#039;saveAs&#039;\n        self.__saveFile()\n\n    def __changeFlag(self, key):\n        &quot;&quot;&quot; \u6587\u672c\u6846\u4fee\u6539\u6807\u5fd7\n        &quot;&quot;&quot;\n        self.__isChanged = True\n\n    def __onClosing(self):\n        &quot;&quot;&quot; \u5173\u95ed\u4e8b\u4ef6\u56de\u8c03\n        &quot;&quot;&quot;\n        if self.__isChanged == True:\n            confirm = askyesnocancel(title=&#039;\u63d0\u9192&#039;, message=&#039;\u662f\u5426\u4fdd\u5b58\uff1f&#039;)\n            if confirm == True:\n                self.__saveFile()\n            elif confirm == None:\n                return\n            else:\n                pass\n\n        self.__master.destroy()\n\n    def __setBg(self):\n        &quot;&quot;&quot; \u8bbe\u7f6e\u80cc\u666f\u989c\u8272\n        &quot;&quot;&quot;\n        self.__bg = askcolor(color=&#039;white&#039;, title=&#039;\u9009\u62e9\u80cc\u666f\u989c\u8272&#039;)\n        self.__text.config(bg=self.__bg[1])\n\n    def __about(self):\n        &quot;&quot;&quot; \u5173\u4e8e\n        &quot;&quot;&quot;\n        showinfo(&#039;\u5173\u4e8e&#039;, &#039;Copyright (C) 2021 IYATT-yx\\niyatt@iyatt.com&#039;)\n\ndef main():\n    root = Tk()\n    root.geometry(&#039;600x400+300+300&#039;)\n    root.title(&#039;\u8bb0\u4e8b\u672c&#039;)\n\n    # \u8bbe\u7f6e\u56fe\u6807\n    # absPath = os.path.dirname(os.path.abspath(__file__))\n    # icon = PhotoImage(file=absPath + &#039;\/notepad.png&#039;)\n    # root.iconphoto(False, icon)\n\n    # \u8bb0\u4e8b\u672c\u754c\u9762\u5b9e\u4f8b\u5316\n    app = Notepad(root)\n    app.createWidgets()\n\n    root.mainloop()\n\nif __name__ == &#039;__main__&#039;:\n    main()<\/code><\/pre>\n<p>\u53ef\u4ee5\u65b0\u5efa\u3001\u4fee\u6539\u4ee5\u53ca\u4fdd\u5b58\u6587\u4ef6\uff0c\u5728\u6587\u672c\u6846\u5185\u5bb9\u53d1\u751f\u4fee\u6539\u540e\uff0c\u8bd5\u56fe\u65b0\u5efa\u3001\u6253\u5f00\u3001\u5173\u95ed\u7b49\u64cd\u4f5c\u4f1a\u8be2\u95ee\u662f\u5426\u4fdd\u5b58\uff0c\u53ef\u4ee5\u8bbe\u7f6e\u80cc\u666f\u663e\u793a\u989c\u8272<br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686032116311.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 620px; --smush-placeholder-aspect-ratio: 620\/474;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686032153709.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 610px; --smush-placeholder-aspect-ratio: 610\/465;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686032174771.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 288px; --smush-placeholder-aspect-ratio: 288\/174;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686032198869.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 506px; --smush-placeholder-aspect-ratio: 506\/351;\" \/><\/p>\n<h3><span class=\"ez-toc-section\" id=\"%E7%AE%80%E6%98%93%E5%9B%BE%E7%89%87%E6%9F%A5%E7%9C%8B%E5%99%A8\"><\/span>\u7b80\u6613\u56fe\u7247\u67e5\u770b\u5668<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre><code class=\"language-python\">&quot;&quot;&quot;\n@brief \u7b80\u6613\u56fe\u7247\u67e5\u770b\u5668\n\nCopyright (C) 2021 IYATT-yx iyatt@iyatt.com\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\nThis program is free software: you can redistribute it and\/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see &lt;https:\/\/www.gnu.org\/licenses\/&gt;.\n&quot;&quot;&quot;\n# pip install opencv-python==4.7.0.72\nimport cv2\nimport tkinter as tk\n# pip install Pillow==9.5.0\n# \u6ce8\u610f\uff1aTkinter \u548c PIL \u4e2d\u90fd\u6709\u540d\u5b57\u4e3a Image \u7684\u7c7b\uff0c\u6240\u4ee5\u8fd9\u91cc\u5bfc\u5165 Tkinter \u6ca1\u6709\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u4ee5\u907f\u514d\u51fa\u73b0\u9519\u8bef\nfrom PIL import ImageTk, Image, UnidentifiedImageError\nfrom tkinter.filedialog import *\nfrom tkinter.messagebox import *\n\nclass Viewer(tk.Frame):\n    def __init__(self, master=None):\n        super().__init__(master)\n        self._master = master\n        self.pack()\n\n    def createWidgets(self):\n        global img\n        self.imgLabel = tk.Label(self)\n        self.imgLabel.pack()\n\n        self._openWay = tk.IntVar(value=1)\n        self.pillow = tk.Radiobutton(self, text=&#039;Pillow&#039;, value=1, variable=self._openWay)\n        self.opencv = tk.Radiobutton(self, text=&#039;OpenCV&#039;, value=2, variable=self._openWay)\n        self.pillow.pack()\n        self.opencv.pack()\n\n        tk.Button(self, text=&#039;\u6253\u5f00&#039;, command=self.openImg).pack()\n\n    def openImg(self):\n        global img\n        fileName = askopenfilename(title=&#039;\u6253\u5f00\u6587\u4ef6&#039;)\n        if not fileName:\n            return\n        try:\n            if self._openWay.get() == 1:  # PIL \u6253\u5f00\u56fe\u7247\n                img = ImageTk.PhotoImage(image=Image.open(fileName))\n            elif self._openWay.get() == 2:  # OpenCV \u6253\u5f00\u56fe\u7247\n                src = cv2.imread(fileName, cv2.IMREAD_COLOR)\n                if src is None:\n                    raise UnidentifiedImageError(&#039;\u4e0d\u80fd\u8bc6\u522b\u56fe\u50cf\u6587\u4ef6 \\&#039;{}\\&#039;&#039;.format(fileName))\n                src = cv2.cvtColor(src, cv2.COLOR_BGR2RGB) # OpenCV \u56fe\u50cf\u6570\u636e\u4e3a BGR \u7684 NumPy \u6570\u7ec4\uff0c\u9700\u8981\u5148\u8f6c\u4e3a RGB\n                img = ImageTk.PhotoImage(image=Image.fromarray(src))\n        except Exception as e:\n            showerror(&quot;\u9519\u8bef&quot;, e)\n            return\n        self.imgLabel.config(image=img)  # \u66f4\u65b0\u56fe\u7247\u663e\u793a\n\ndef main():\n    global img\n    img = &#039;&#039;\n    root = tk.Tk()\n    root.geometry(&#039;600x500+300+200&#039;)\n    root.title(&#039;\u7b80\u5355\u56fe\u7247\u67e5\u770b\u5668&#039;)\n    viewer = Viewer(root)\n    viewer.createWidgets()\n    root.mainloop()\n\nif __name__ == &#039;__main__&#039;:\n    main()<\/code><\/pre>\n<p>\u8fd9\u91cc\u63d0\u4f9b\u4e86\u4e24\u79cd\u601d\u8def\u6253\u5f00\u56fe\u7247\u6587\u4ef6\uff0c\u4e00\u79cd\u662f\u76f4\u63a5\u4f7f\u7528 Pillow\uff0c\u53e6\u5916\u4e00\u79cd\u662f\u4f7f\u7528 OpenCV\uff0c\u7136\u540e\u518d\u8f6c\u6362\u6570\u636e\u7c7b\u578b\uff08\u641e\u61c2\u8fd9\u4e2a\uff0c\u5c31\u53ef\u4ee5\u5c06 OpenCV \u4e0e Tkinter \u878d\u5408\u5f00\u53d1\uff09\uff0c\u5176\u5b83\u4e00\u4e9b\u56fe\u50cf\u6570\u636e\u7c7b\u578b\u53ef\u4ee5\u53c2\u8003\uff1a<a href=\"https:\/\/blog.iyatt.com\/?p=2592\">https:\/\/blog.iyatt.com\/?p=2592<\/a> \u3002<br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686074656320.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 249px; --smush-placeholder-aspect-ratio: 249\/181;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686074674085.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 565px; --smush-placeholder-aspect-ratio: 565\/440;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686074885169.png\" alt=\"\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 202px; --smush-placeholder-aspect-ratio: 202\/267;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686104606703.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 403px; --smush-placeholder-aspect-ratio: 403\/220;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686075004252.png\" alt=\"\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 721px; --smush-placeholder-aspect-ratio: 721\/912;\" \/><\/p>\n<h3><span class=\"ez-toc-section\" id=\"%E6%91%84%E5%83%8F%E5%A4%B4%E9%A2%84%E8%A7%88\"><\/span>\u6444\u50cf\u5934\u9884\u89c8<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre><code class=\"language-python\">&quot;&quot;&quot;\n@brief \u6444\u50cf\u5934\u9884\u89c8\n\nCopyright (C) 2023 IYATT-yx iyatt@iyatt.com\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\nThis program is free software: you can redistribute it and\/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see &lt;https:\/\/www.gnu.org\/licenses\/&gt;.\n&quot;&quot;&quot;\n# Windows 11 \u4e13\u4e1a\u5de5\u4f5c\u7ad9\u7248 22H2\n# Python 3.11.4\n# pip install opencv-python==4.7.0.72\nimport tkinter as tk\nimport cv2\n# pip install Pillow==9.5.0\nfrom PIL import ImageTk, Image\n\nclass CameraPreview(tk.Frame):\n    def __init__(self, master=None):\n        super().__init__(master)\n        self.__master = master\n        self.__master.title(&#039;\u6444\u50cf\u5934\u9884\u89c8&#039;)\n        self.__master.geometry(&#039;800x600&#039;)\n        self.__master.protocol(&#039;WM_DELETE_WINDOW&#039;, self.__on_closing) # \u5173\u95ed\u4e8b\u4ef6\n        self.pack()\n        self.__cap = None # \u89c6\u9891\u6355\u83b7\u5bf9\u8c61\n        self.__state = False # \u56fe\u50cf\u66f4\u65b0\u6807\u5fd7\n        self.__create_widgets()\n\n    def __create_widgets(self):\n        &quot;&quot;&quot; \u521b\u5efa\u7a97\u53e3\u7ec4\u4ef6 &quot;&quot;&quot;\n        # \u56fe\u50cf\u9884\u89c8\n        self.__image_preview_label = tk.Label(self, text=&#039;\u6682\u65e0\u56fe\u50cf&#039;)\n        self.__image_preview_label.pack()\n\n        # \u89c6\u9891\u6e90\u8f93\u5165\n        self.__video_source_entry = tk.Entry(self)\n        self.__video_source_entry.pack()\n\n        # \u89c6\u9891\u6e90\u6253\u5f00\n        tk.Button(self, text=&#039;\u6253\u5f00&#039;, command=self.__on_open_video_source_button).pack()\n\n        # \u56fe\u50cf\u9884\u89c8\u66f4\u65b0\n        self.__master.after(100, self.__update_image_preview_label)\n\n    def __on_open_video_source_button(self):\n        &quot;&quot;&quot; \u6253\u5f00\u6309\u94ae\u56de\u8c03 &quot;&quot;&quot;\n        self.video_source = self.__video_source_entry.get()\n        self.__state = False\n        if self.__cap != None:\n            self.__cap.release()\n            print(&#039;\u91ca\u653e\u65e7\u89c6\u9891\u8d44\u6e90&#039;)\n        if len(self.video_source) == 0:\n            self.__cap = None\n            print(&#039;\u8bf7\u586b\u5199\u89c6\u9891\u6e90&#039;)\n            return\n        if self.video_source.isdigit():\n            self.video_source = int(self.video_source)\n        try:\n            self.__cap = cv2.VideoCapture(self.video_source)\n        except Exception as e:\n            print(e)\n        if not self.__cap.isOpened():\n            self.__cap = None\n            print(&#039;\u8bf7\u68c0\u67e5\u89c6\u9891\u6e90 {} \u662f\u5426\u53ef\u7528&#039;.format(self.video_source))\n            return\n        print(&#039;\u6253\u5f00\u89c6\u9891\u6e90\uff1a{}&#039;.format(self.video_source))\n        self.__state = True\n\n    def __on_closing(self):\n        &quot;&quot;&quot; \u5173\u95ed\u4e8b\u4ef6\u5904\u7406 &quot;&quot;&quot;\n        if self.__cap != None:\n            self.__cap.release()\n            print(&#039;\u91ca\u653e\u89c6\u9891\u8d44\u6e90&#039;)\n        self.__master.destroy()\n        print(&#039;\u9500\u6bc1\u7a97\u53e3&#039;)\n\n    def __image_convert(self, src):\n        &quot;&quot;&quot; OpenCV \u56fe\u50cf\u8f6c Tkinter &quot;&quot;&quot;\n        src = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)\n        return ImageTk.PhotoImage(image=Image.fromarray(src))\n\n    def __update_image_preview_label(self):\n        if self.__state:\n            ret, src = self.__cap.read()\n            if ret:\n                self.__img = self.__image_convert(src)\n                self.__image_preview_label.config(image=self.__img)\n        self.__master.after(100, self.__update_image_preview_label)\n\ndef main():\n    root = tk.Tk()\n    cp = CameraPreview(root)\n    cp.mainloop()\n\nif __name__ == &#039;__main__&#039;:\n    main()<\/code><\/pre>\n<p><img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686460006896.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 809px; --smush-placeholder-aspect-ratio: 809\/647;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686460058050.png\" alt=\"\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 812px; --smush-placeholder-aspect-ratio: 812\/742;\" \/><br \/>\n<img decoding=\"async\" data-src=\"https:\/\/blog.iyatt.com\/wp-content\/uploads\/2023\/06\/image-1686460093539.png\" alt=\"file\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 162px; --smush-placeholder-aspect-ratio: 162\/113;\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u524d\u8a00 \u8fd9\u4e9b\u4e3b\u8981\u662f 21 \u5e74\u7684\u65f6\u5019\u5b66\u4e60 Python \u7684\u5b98\u65b9\u56fe\u5f62\u5e93 Tkinter \u65f6\u5199\u7684\uff0c\u5728\u5199\u6bd4\u8f83\u7b80\u5355\u7684\u5de5\u5177\u7684 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"zakra_page_container_layout":"customizer","zakra_page_sidebar_layout":"customizer","zakra_remove_content_margin":false,"zakra_sidebar":"customizer","zakra_transparent_header":"customizer","zakra_logo":0,"zakra_main_header_style":"default","zakra_menu_item_color":"","zakra_menu_item_hover_color":"","zakra_menu_item_active_color":"","zakra_menu_active_style":"","zakra_page_header":true,"_lmt_disableupdate":"no","_lmt_disable":"no","footnotes":""},"categories":[1,592],"tags":[],"class_list":["post-10258","post","type-post","status-publish","format-standard","hentry","category-all","category-python"],"modified_by":"IYATT-yx","_links":{"self":[{"href":"https:\/\/blog.iyatt.com\/index.php?rest_route=\/wp\/v2\/posts\/10258","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.iyatt.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.iyatt.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.iyatt.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.iyatt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10258"}],"version-history":[{"count":0,"href":"https:\/\/blog.iyatt.com\/index.php?rest_route=\/wp\/v2\/posts\/10258\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.iyatt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10258"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.iyatt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10258"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.iyatt.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10258"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}