软件代做:利用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/

posted @ 2020-09-10 16:55  码上无忧  阅读(962)  评论(0编辑  收藏  举报