軟件代做:利用Python編寫一個行業專用的小計算器


前言:本文講述的是如何利用python編程制作一個適用於指定行業的計算器,方便計算結果,涵蓋的知識點由Python編寫GUI界面程序,利用爬蟲采集實時的匯率數據,將Python文件打包成可以單獨運行的exe文件。

首先,分析我們的需求,編寫一個適用於指定行業的計算器,這里我們用到的計算公式很簡單,就是淘寶提供的金石定價公式,如下圖所示

淘寶定價計算器

 

這里可以看到這個計算公式還是蠻簡單的,對於Python來說也就是一行代碼的事,那么我們就開始着手寫代碼,首先搭建我們的頁面布局,這里我們采用的是tkinter,這個框架在畫GUI方面還是很簡單方便的,首先給大家展示下我的最終布局,如下圖所示

最終樣式

其實也不是很好看,不過我已經盡我所能去美化了,其實功能很簡單,就是幾個輸入框,兩個按鈕,點擊計算按鈕,獲取輸入框中的值,通過Python代碼計算結果,最后將計算結果寫入指定的輸入框中,關於tkinter的組件介紹,可以自行百度,我這里就直接上代碼了

class Application(tk.Tk):
    def __init__(self):
            super().__init__()
            self.createUI()

    def createUI(self):

        self.ft = tf.Font(family='微軟雅黑', size=18,weight=tf.BOLD)

        self.ft1 = tf.Font(family='微軟雅黑', size=12)

        self.fm = tk.Frame(self)

        self.label = tk.Label(self.fm,text="計算結果:",font=self.ft)
        self.label.pack(side=tk.LEFT)

        self.fm_new1 = tk.Frame(self.fm)

        self.label0 = tk.Label(self.fm_new1,text="人民幣:",font=self.ft1)
        self.label0.pack(side=tk.LEFT)

        self.entry0 = tk.Entry(self.fm_new1,font=self.ft1)
        self.entry0.pack(side=tk.LEFT)

        self.label11 = tk.Label(self.fm_new1,text="美元:",font=self.ft1)
        self.label11.pack(side=tk.LEFT)


        self.entry11 = tk.Entry(self.fm_new1,font=self.ft1)
        self.entry11.pack(side=tk.LEFT)

        self.fm_new1.pack(side=tk.TOP,padx=5, pady=10)

        self.fm_new2 = tk.Frame(self.fm)

        self.label12 = tk.Label(self.fm_new2,text="新加坡幣:",font=self.ft1)
        self.label12.pack(side=tk.LEFT)


        self.entry12 = tk.Entry(self.fm_new2,font=self.ft1)
        self.entry12.pack(side=tk.LEFT)

        self.label13 = tk.Label(self.fm_new2,text="日元:",font=self.ft1)
        self.label13.pack(side=tk.LEFT)


        self.entry13 = tk.Entry(self.fm_new2,font=self.ft1)
        self.entry13.pack(side=tk.LEFT)

        self.fm_new2.pack(side=tk.TOP,padx=5, pady=10)

        self.fm.pack(side=tk.TOP,padx=5, pady=10)

        self.fm1 = tk.Frame(self)

        self.label1 = tk.Label(self.fm1,text="金 重:",font=self.ft1)
        self.label1.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry1 = tk.Entry(self.fm1,font=self.ft1)
        self.entry1.pack(side=tk.LEFT,padx=5, pady=10)

        self.label10 = tk.Label(self.fm1,text="浮動比率:",font=self.ft1)
        self.label10.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry10 = tk.Entry(self.fm1,font=self.ft1)
        self.entry10.pack(side=tk.LEFT,anchor=tk.W,padx=5, pady=10)


        self.fm1.pack(side=tk.TOP,padx=5, pady=5)

        self.fm2 = tk.Frame(self)

        self.label2 = tk.Label(self.fm2,text="金 價:",font=self.ft1)
        self.label2.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry2 = tk.Entry(self.fm2,font=self.ft1)
        self.entry2.pack(side=tk.LEFT,padx=5, pady=10)

        self.labe3 = tk.Label(self.fm2,text="14K/18K:",font=self.ft1)
        self.labe3.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry3 = tk.Entry(self.fm2,font=self.ft1)
        self.entry3.pack(side=tk.LEFT,padx=5, pady=10)


        self.fm2.pack(side=tk.TOP,padx=5, pady=5)

        self.fm3 = tk.Frame(self)

        self.label4 = tk.Label(self.fm3,text="主石重:",font=self.ft1)
        self.label4.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry4 = tk.Entry(self.fm3,font=self.ft1)
        self.entry4.pack(side=tk.LEFT,padx=5, pady=10)

        self.label5 = tk.Label(self.fm3,text="價  格:",font=self.ft1)
        self.label5.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry5 = tk.Entry(self.fm3,font=self.ft1)
        self.entry5.pack(side=tk.LEFT,padx=5, pady=10)


        self.fm3.pack(side=tk.TOP,padx=5, pady=5)

        self.fm4 = tk.Frame(self)

        self.label6 = tk.Label(self.fm4,text="副石重:",font=self.ft1)
        self.label6.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry6 = tk.Entry(self.fm4,font=self.ft1)
        self.entry6.pack(side=tk.LEFT,padx=5, pady=10)

        self.labe7 = tk.Label(self.fm4,text="價  格:",font=self.ft1)
        self.labe7.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry7 = tk.Entry(self.fm4,font=self.ft1)
        self.entry7.pack(side=tk.LEFT,padx=5, pady=10)



        self.fm4.pack(side=tk.TOP,padx=5, pady=5)

        self.fm5 = tk.Frame(self)

        self.label8 = tk.Label(self.fm5,text="工費:",font=self.ft1)
        self.label8.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry8 = tk.Entry(self.fm5,font=self.ft1)
        self.entry8.pack(side=tk.LEFT,padx=5, pady=10)

        self.labe9 = tk.Label(self.fm5,text="設計費:",font=self.ft1)
        self.labe9.pack(side=tk.LEFT,padx=5, pady=10)

        self.entry9 = tk.Entry(self.fm5,font=self.ft1)
        self.entry9.pack(side=tk.LEFT,padx=10, pady=10)


        self.fm5.pack(side=tk.TOP,padx=5, pady=5)


        self.fm6 = tk.Frame(self)
        self.selectButton = tk.Button(self.fm6, text="重置", command=self.selectFile,font=self.ft1)
        self.selectButton.pack(side=tk.LEFT,padx=10, pady=10)

        self.startButton = tk.Button(self.fm6, text="計算", command=lambda :self.thread_it(self.startAction),font=self.ft1)
        self.startButton.pack(side=tk.LEFT,padx=10, pady=10)

        self.fm6.pack(side=tk.TOP,padx=5, pady=5)

        self.title("我的計算器")
        #窗口大小
        width ,height= 600, 500
        #窗口居中顯示
        self.geometry('%dx%d+%d+%d' % (width,height,(self.winfo_screenwidth() - width ) / 2, (self.winfo_screenheight() - height) / 2))
        #窗口最大值
        self.maxsize(600, 500)
        #窗口最小值
        self.minsize(300,200)

        self.entry0.insert('end',0)
        self.entry1.insert('end',0)
        self.entry2.insert('end',0)
        self.entry3.insert('end',0)
        self.entry4.insert('end',0)
        self.entry5.insert('end',0)
        self.entry6.insert('end',0)
        self.entry7.insert('end',0)
        self.entry8.insert('end',150)
        self.entry9.insert('end',50)
        self.entry10.insert('end',1.25)
        self.entry11.insert('end',0)
        self.entry12.insert('end',0)
        self.entry13.insert('end',0)

說實話這段代碼寫的很隨意,變量命名很隨意,因為很多都是重復的東西,這里大致講一下,首先是創建定義一個類繼承自tkinter,這就相當於整個對象就是一個窗體了,之后就在這個窗體中進行布局,這里我們采用的是pack布局,說白了就是浮動布局,就是按照一行或者一列依次排列組件,這里就是利用Frame組件生成了幾行的布局,然后在每個Frame里排列我們的標簽和輸入框,其中包含的一些細節就是組件的字體,組件之間的間距之類,完成了布局這一步之后,我們需要給按鈕綁定事件,就是點擊按鈕觸發什么操作,這里我們有兩個按鈕。

其中重置按鈕是為了清除輸入的錯誤數據,綁定的事件就用command=self.selectFile這行代碼來指定,這樣就可以綁定到selectFile這個函數上,這個函數的代碼如下所示

    def selectFile(self):
        self.entry1.delete(0, "end")
        self.entry4.delete(0, "end")
        self.entry6.delete(0, "end")

        self.entry1.insert('end',0)
        self.entry4.insert('end',0)
        self.entry6.insert('end',0)

然后計算按鈕是為了執行計算操作,這里我們采用了線程的方式進行綁定,也就是異步執行,不會卡住,避免因計算量過大導致程序假死的現象,綁定的方式是command=lambda :self.thread_it(self.startAction)

綁定的函數如下所示

    def startAction(self):
        A = self.entry1.get()
        print(A)
        B = self.entry2.get()
        print(B)
        C = self.entry3.get()
        print(C)
        D = self.entry4.get()
        print(D)
        E = self.entry5.get()
        print(E)
        F = self.entry6.get()
        print(F)
        G = self.entry7.get()
        print(G)
        H = self.entry8.get()
        print(H)
        I = self.entry9.get()
        print(I)
        J = self.entry10.get()
        print(J)
        result = ((float(A)*float(B)*float(C))+(float(D)*float(E))+(float(F)*float(G))+(float(H)+float(I)))*float(J)
        USDCNY,SGDCNY,JPYCNY = self.getRate()
        USDCNY_result = result/USDCNY
        SGDCNY_result = result/SGDCNY
        JPYCNY_result = USDCNY_result*JPYCNY
        self.entry0.delete(0, "end")
        self.entry0.insert('end',str(round(result, 2)))

        self.entry11.delete(0, "end")
        self.entry11.insert('end',str(round(USDCNY_result, 2)))

        self.entry12.delete(0, "end")
        self.entry12.insert('end',str(round(SGDCNY_result, 2)))

        self.entry13.delete(0, "end")
        self.entry13.insert('end',str(round(JPYCNY_result, 2)))
    @staticmethod
    def thread_it(func, *args):
        t = threading.Thread(target=func, args=args) 
        t.setDaemon(True)   
        t.start()  

至此基本完成了,不過完成的軟件是這樣的,如下所示

初始版本

可以看到比較明顯的差異在計算結果那塊,因為后面和客戶溝通了,他需要其他幣種的計算結果,所以后面就增加了幾種結果,這里就用到了爬蟲技術去采集實時的匯率,這里直接奉上了代碼,直接解析的接口數據,所以很簡單

    def getRate(self):
        url = "http://webforex.hermes.hexun.com/forex/quotelist?code=FOREXUSDCNY,FOREXSGDCNY,FOREXUSDJPY&column=Code,Price"
        req = urllib.request.Request(url)
        f = urllib.request.urlopen(req)
        html = f.read().decode("utf-8")
        print(html)

        s = re.findall("{.*}",str(html))[0]
        sjson = json.loads(s)

        USDCNY = sjson["Data"][0][0][1]/10000
        print(USDCNY)

        SGDCNY = sjson["Data"][0][1][1]/10000
        print(SGDCNY)

        JPYCNY = sjson["Data"][0][2][1]/10000
        print(JPYCNY)

        return USDCNY,SGDCNY,JPYCNY

至此,Python代碼基本完成了,這里奉上完整的代碼

import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import threading
import tkinter.font as tf
import re
import json
import urllib.request


class Application(tk.Tk):
    def __init__(self):
            super().__init__()
            self.createUI()

    def createUI(self):

        self.ft = tf.Font(family='微軟雅黑', size=18,weight=tf.BOLD)

        self.ft1 = tf.Font(family='微軟雅黑', size=12)

        self.fm = tk.Frame(self)

        self.label = tk.Label(self.fm,text="計算結果:",font=self.ft)
        self.label.pack(side=tk.LEFT)

        self.fm_new1 = tk.Frame(self.fm)

        self.label0 = tk.Label(self.fm_new1,text="人民幣:",font=self.ft1)
        self.label0.pack(side=tk.LEFT)

        self.entry0 = tk.Entry(self.fm_new1,font=self.ft1)
        self.entry0.pack(side=tk.LEFT)

        self.label11 = tk.Label(self.fm_new1,text="美元:",font=self.ft1)
        self.label11.pack(side=tk.LEFT)


        self.entry11 = tk.Entry(self.fm_new1,font=self.ft1)
        self.entry11.pack(side=tk.LEFT)

        self.fm_new1.pack(side=tk.TOP,padx=5, pady=10)

        self.fm_new2 = tk.Frame(self.fm)

        self.label12 = tk.Label(self.fm_new2,text="新加坡幣:",font=self.ft1)
        self.label12.pack(side=tk.LEFT)


        self.entry12 = tk.Entry(self.fm_new2,font=self.ft1)
        self.entry12.pack(side=tk.LEFT)

        self.label13 = tk.Label(self.fm_new2,text="日元:",font=self.ft1)
        self.label13.pack(side=tk.LEFT)


        self.entry13 = tk.Entry(self.fm_new2,font=self.ft1)
        self.entry13.pack(side=tk.LEFT)

        self.fm_new2.pack(side=tk.TOP,padx=5, pady=10)

        self.fm.pack(side=tk.TOP,padx=5, pady=10)

        self.fm1 = tk.Frame(self)

        self.label1 = tk.Label(self.fm1,text="金 重:",font=self.ft1)
        self.label1.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry1 = tk.Entry(self.fm1,font=self.ft1)
        self.entry1.pack(side=tk.LEFT,padx=5, pady=10)

        self.label10 = tk.Label(self.fm1,text="浮動比率:",font=self.ft1)
        self.label10.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry10 = tk.Entry(self.fm1,font=self.ft1)
        self.entry10.pack(side=tk.LEFT,anchor=tk.W,padx=5, pady=10)


        self.fm1.pack(side=tk.TOP,padx=5, pady=5)

        self.fm2 = tk.Frame(self)

        self.label2 = tk.Label(self.fm2,text="金 價:",font=self.ft1)
        self.label2.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry2 = tk.Entry(self.fm2,font=self.ft1)
        self.entry2.pack(side=tk.LEFT,padx=5, pady=10)

        self.labe3 = tk.Label(self.fm2,text="14K/18K:",font=self.ft1)
        self.labe3.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry3 = tk.Entry(self.fm2,font=self.ft1)
        self.entry3.pack(side=tk.LEFT,padx=5, pady=10)


        self.fm2.pack(side=tk.TOP,padx=5, pady=5)

        self.fm3 = tk.Frame(self)

        self.label4 = tk.Label(self.fm3,text="主石重:",font=self.ft1)
        self.label4.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry4 = tk.Entry(self.fm3,font=self.ft1)
        self.entry4.pack(side=tk.LEFT,padx=5, pady=10)

        self.label5 = tk.Label(self.fm3,text="價  格:",font=self.ft1)
        self.label5.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry5 = tk.Entry(self.fm3,font=self.ft1)
        self.entry5.pack(side=tk.LEFT,padx=5, pady=10)


        self.fm3.pack(side=tk.TOP,padx=5, pady=5)

        self.fm4 = tk.Frame(self)

        self.label6 = tk.Label(self.fm4,text="副石重:",font=self.ft1)
        self.label6.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry6 = tk.Entry(self.fm4,font=self.ft1)
        self.entry6.pack(side=tk.LEFT,padx=5, pady=10)

        self.labe7 = tk.Label(self.fm4,text="價  格:",font=self.ft1)
        self.labe7.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry7 = tk.Entry(self.fm4,font=self.ft1)
        self.entry7.pack(side=tk.LEFT,padx=5, pady=10)



        self.fm4.pack(side=tk.TOP,padx=5, pady=5)

        self.fm5 = tk.Frame(self)

        self.label8 = tk.Label(self.fm5,text="工費:",font=self.ft1)
        self.label8.pack(side=tk.LEFT,padx=10, pady=10)

        self.entry8 = tk.Entry(self.fm5,font=self.ft1)
        self.entry8.pack(side=tk.LEFT,padx=5, pady=10)

        self.labe9 = tk.Label(self.fm5,text="設計費:",font=self.ft1)
        self.labe9.pack(side=tk.LEFT,padx=5, pady=10)

        self.entry9 = tk.Entry(self.fm5,font=self.ft1)
        self.entry9.pack(side=tk.LEFT,padx=10, pady=10)


        self.fm5.pack(side=tk.TOP,padx=5, pady=5)


        self.fm6 = tk.Frame(self)
        self.selectButton = tk.Button(self.fm6, text="重置", command=self.selectFile,font=self.ft1)
        self.selectButton.pack(side=tk.LEFT,padx=10, pady=10)

        self.startButton = tk.Button(self.fm6, text="計算", command=lambda :self.thread_it(self.startAction),font=self.ft1)
        self.startButton.pack(side=tk.LEFT,padx=10, pady=10)

        self.fm6.pack(side=tk.TOP,padx=5, pady=5)

        self.title("我的計算器")
        #窗口大小
        width ,height= 600, 500
        #窗口居中顯示
        self.geometry('%dx%d+%d+%d' % (width,height,(self.winfo_screenwidth() - width ) / 2, (self.winfo_screenheight() - height) / 2))
        #窗口最大值
        self.maxsize(600, 500)
        #窗口最小值
        self.minsize(300,200)

        self.entry0.insert('end',0)
        self.entry1.insert('end',0)
        self.entry2.insert('end',0)
        self.entry3.insert('end',0)
        self.entry4.insert('end',0)
        self.entry5.insert('end',0)
        self.entry6.insert('end',0)
        self.entry7.insert('end',0)
        self.entry8.insert('end',150)
        self.entry9.insert('end',50)
        self.entry10.insert('end',1.25)
        self.entry11.insert('end',0)
        self.entry12.insert('end',0)
        self.entry13.insert('end',0)

    def selectFile(self):
        self.entry1.delete(0, "end")
        self.entry4.delete(0, "end")
        self.entry6.delete(0, "end")

        self.entry1.insert('end',0)
        self.entry4.insert('end',0)
        self.entry6.insert('end',0)


    def startAction(self):
        A = self.entry1.get()
        print(A)
        B = self.entry2.get()
        print(B)
        C = self.entry3.get()
        print(C)
        D = self.entry4.get()
        print(D)
        E = self.entry5.get()
        print(E)
        F = self.entry6.get()
        print(F)
        G = self.entry7.get()
        print(G)
        H = self.entry8.get()
        print(H)
        I = self.entry9.get()
        print(I)
        J = self.entry10.get()
        print(J)
        result = ((float(A)*float(B)*float(C))+(float(D)*float(E))+(float(F)*float(G))+(float(H)+float(I)))*float(J)
        USDCNY,SGDCNY,JPYCNY = self.getRate()
        USDCNY_result = result/USDCNY
        SGDCNY_result = result/SGDCNY
        JPYCNY_result = USDCNY_result*JPYCNY
        self.entry0.delete(0, "end")
        self.entry0.insert('end',str(round(result, 2)))

        self.entry11.delete(0, "end")
        self.entry11.insert('end',str(round(USDCNY_result, 2)))

        self.entry12.delete(0, "end")
        self.entry12.insert('end',str(round(SGDCNY_result, 2)))

        self.entry13.delete(0, "end")
        self.entry13.insert('end',str(round(JPYCNY_result, 2)))
    @staticmethod
    def thread_it(func, *args):
        t = threading.Thread(target=func, args=args) 
        t.setDaemon(True)   
        t.start()  

    def getRate(self):
        url = "http://webforex.hermes.hexun.com/forex/quotelist?code=FOREXUSDCNY,FOREXSGDCNY,FOREXUSDJPY&column=Code,Price"
        req = urllib.request.Request(url)
        f = urllib.request.urlopen(req)
        html = f.read().decode("utf-8")
        print(html)

        s = re.findall("{.*}",str(html))[0]
        sjson = json.loads(s)

        USDCNY = sjson["Data"][0][0][1]/10000
        print(USDCNY)

        SGDCNY = sjson["Data"][0][1][1]/10000
        print(SGDCNY)

        JPYCNY = sjson["Data"][0][2][1]/10000
        print(JPYCNY)

        return USDCNY,SGDCNY,JPYCNY


app = Application()
app.mainloop()

# root.mainloop()

但是到這一步,還差一點點,因為我們的目的是生成一個exe軟件,可以給沒有安裝Python環境的人使用,所以我們要用到Python的軟件打包工具,這里我們使用的是pyinstaller,使用起來也很方便,直接用命令行進入python文件所在的文件夾,執行pyinstaller -F app.py --noconsole 即可,這里的app.py指代的是你們需要打包的python文件名,--noconsole是指打包成的exe文件運行時不顯示控制台黑窗口。執行完成即可在同級目錄下的dist文件中找到你們打包好的exe文件,至此,本文結束。

最終樣式

本文首發於https://www.bizhibihui.com/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM