Python | GUI小項目_數(shù)據(jù)庫批量處理器1.0

平時的 Python 學習過程比較枯燥,想要保持興趣和提高,就得上手親自做一些小項目
本次小項目是利用 Python 自帶的 tkinter 模塊構造簡單的 GUI伞辛,利用PyMySQL 對數(shù)據(jù)庫進行操作 对室,數(shù)據(jù)存儲利用 json模塊隧甚,這些都是比較基礎的東西,做的過程可以逐漸熟悉上手

此工具可應用于多個數(shù)據(jù)庫存在相同的表名等情況下峦树,進行批量操作

開發(fā)環(huán)境如下:

  • Python 3.6.6
  • MySQL 8.0
  • PyMySQL 0.9.2 (pip即可)
  • IDE:Geany

先來看看項目完成的界面

主界面

主界面.PNG

添加鍵界面

添加界面.PNG

功能說明
1辣辫、左上方是 SQL 語句輸入欄,輸入語句后點執(zhí)行按鍵魁巩,執(zhí)行按鍵會從本地存儲的 json 文件獲取數(shù)據(jù)庫信息急灭,連接數(shù)據(jù)庫,然后執(zhí)行語句歪赢,再關閉數(shù)據(jù)庫
2化戳、主界面有 2 個清屏按鍵,分別為語句清屏和 Info 清屏;語句清屏点楼,顧名思義是將 SQL 語句清除扫尖, Info 清屏是將下方的執(zhí)行信息欄的報錯清空
3、退出程序按鍵掠廓,退出該程序
4换怖、添加按鍵,點擊后彈出添加界面蟀瞧,有 6 個輸入欄沉颂,其中一個帶有默認值, 6 欄全部輸入信息才能點擊確認悦污,否則出現(xiàn)提示框提示將信息填寫完整铸屉,取消即退出該界面;點擊確認后切端,新的數(shù)據(jù)庫信息將保存到本地 json 文件中彻坛,同時將已保存的數(shù)據(jù)庫信息清空,提示更新鍵更新
5踏枣、刪除按鍵昌屉,點擊后,刪除已保存的數(shù)據(jù)庫框中選中的數(shù)據(jù)庫茵瀑,同時本地 json 文件會刪除相應的信息
6间驮、更新按鍵,點擊后马昨,獲取本地 json 文件數(shù)據(jù)竞帽,同時將數(shù)據(jù)更新到上方的框中
7、執(zhí)行信息欄偏陪,在程序報錯時抢呆,欄中將出現(xiàn)相對應的報錯信息

!由于是練手項目笛谦,基本功能不影響的情況存在未知BUG抱虐,以后在實際應用中修改BUG,再重構優(yōu)化

話不多說饥脑,根據(jù)實際開發(fā)過程中恳邀,下面依開發(fā)思路進行分解

1、先根據(jù)需求對GUI界面進行分解灶轰、排版

  • 需要3個標簽對信息框介紹——3個Label
  • 需要7個按鍵實現(xiàn)不同的功能——7個Button
  • 需要3個框谣沸,分別用來輸入SQL語句、展示數(shù)據(jù)庫信息笋颤、展示操作中發(fā)生的必要信息——2個scrolledtext乳附、1個Listbox

我的布局圖

布局.png

PS:實際可以更簡單内地,不需要分這么多塊,但也是第一開發(fā)赋除,經(jīng)驗不足阱缓,Frame可有可無,方便分塊举农,看實際情況

此時應有

from tkinter import *
from tkinter import scrolledtext
def main():
    root = Tk()

    # Frame
    frmA1 = Frame()
    frmA2 = Frame()
    frmA3 = Frame()
    frmB1 = Frame()
    frmB2 = Frame()
    frmB3 = Frame()
    frmC =  Frame()

    # Label
    label_1 = Label(frmA1)
    label_2 = Label(frmB1)
    label_3 = Label(frmC)

    # scrolledtext
    scrt_1 = scrolledtext.ScrolledText(frmA2)
    scrt_2 = scrolledtext.ScrolledText(frmC)

    # Listbox
    scrollbar = Scrollbar(frmB2)
    listbox = Listbox(frmB2)

    # Button
    button_1 = Button(frmA3)
    button_2 = Button(frmA3)
    button_3 = Button(frmA3)
    button_4 = Button(frmB3)
    button_5 = Button(frmB3)
    button_6 = Button(frmB3)
    button_7 = Button(frmC)

    # 窗口布局
    frmA1.grid()
    frmA2.grid()
    frmA3.grid()
    frmB1.grid()
    frmB2.grid()
    frmB3.grid()
    frmC.grid()
        
    label_1.grid()
    label_2.grid()
    label_3.grid()
        
    scrt_1.grid()
    scrt_2.grid()
    
    scrollbar.grid()
    listbox.grid()

    button_1.grid()
    button_2.grid()
    button_3.grid()
    button_4.grid()
    button_5.grid()
    button_6.grid()
    button_7.grid()

    root.mainloop()

if __name__ == '__main__':
    main()

將所有需要的控件寫出來后荆针,需要對各個控件進行重命名、屬性的添加颁糟,布局的調整航背,寬度和高度沒有設置好以及grid調用時,一般都會出現(xiàn)不整齊的現(xiàn)象棱貌,這些都要需要花時間去慢慢調整玖媚,下面是完成后的代碼

    # 主界面
    root = Tk()
    root.title('數(shù)據(jù)庫批量處理器')
    root.resizable(0, 0)

    # Frame
    frm_width = 380
    frm_height1 = 200
    frm_height2 = 50
    frmA1 = Frame(width=frm_width, height=frm_height2-5)
    frmA2 = Frame(width=frm_width, height=frm_height1)
    frmA3 = Frame(width=frm_width, height=frm_height2)
    frmB1 = Frame(width=frm_width, height=frm_height2-5)
    frmB2 = Frame(width=frm_width, height=frm_height1)
    frmB3 = Frame(width=frm_width, height=frm_height2)
    frmC =  Frame(width=frm_width*2, height=frm_height1+30)

    # Label
    infotext = '執(zhí)' + 18*' ' + '行' + 18*' ' + '信' + 18*' ' + '息' + 18*' ' + '欄'
    input_label = Label(frmA1, text='SQL   語   句   輸   入   欄', width=54, height=2, anchor='center', relief='groove', foreground='red', bd=3)
    db_label =    Label(frmB1, text='已   保   存   的   數(shù)   據(jù)   庫', width=54, height=2, anchor='center', relief='groove', foreground='red', bd=3)
    info_label =  Label(frmC, text=infotext, width=90, height=2, foreground='red', relief='groove', bd=3)

    # scrolledtext
    input_text = scrolledtext.ScrolledText(frmA2, width=51, height=15, wrap=WORD)
    info_text =  scrolledtext.ScrolledText(frmC, width=105, height=13, wrap=WORD, state='normal')
    
    # Listbox
    scr = Scrollbar(frmB2, width=16)
    db_list = Listbox(frmB2, width=51, height=11, yscrollcommand=scr.set)
    scr.config(command=db_list.yview)
    
    # Button
    button_width = 16
    button_height = 2
    exe_button =    Button(frmA3, text='執(zhí) 行', width=button_width, height=button_height, foreground='blue', command=exe_input, relief='groove')
    clear1_button = Button(frmA3, text='語 句 清 屏', width=button_width, height=button_height, foreground='blue', command=clear_input1, relief='groove')
    quit_button =   Button(frmA3, text='退 出 程 序', width=button_width, height=button_height, foreground='blue', command=quitcommand, relief='groove')
    add_button =    Button(frmB3, text='添 加', width=button_width, height=button_height, foreground='blue', command=create_add_frame, relief='groove')
    del_button =    Button(frmB3, text='刪 除', width=button_width, height=button_height, foreground='blue', relief='groove', command=del_db)
    update_button = Button(frmB3, text='更 新', width=button_width, height=button_height, foreground='blue', relief='groove', command=update_db_info)
    clear2_button = Button(frmC, text='Info 清 屏', width=button_width, height=button_height, foreground='blue', command=clear_input2, relief='groove')

    # 窗口布局
    frmA1.grid(row=0, column=0)
    frmA2.grid(row=1, column=0)
    frmA3.grid(row=2, column=0)
    frmB1.grid(row=0, column=1)
    frmB2.grid(row=1, column=1)
    frmB3.grid(row=2, column=1)
    frmC.grid(row=3, column=0, columnspan=3)

    input_label.grid(row=0, column=0, padx=1, pady=1)
    db_label.grid(row=0, column=1, padx=1, pady=1)
    info_label.grid(row=0, column=0)
    
    input_text.grid(row=0, column=0)
    info_text.grid(row=1, columnspan=2)
    
    db_list.grid(row=0, column=0)
    scr.grid(row=0, column=1, ipady=80)
    
    exe_button.grid(row=0, column=0, ipadx=1, pady=1)
    clear1_button.grid(row=0, column=1, padx=1, pady=1)
    quit_button.grid(row=0, column=2, padx=1, pady=1)
    add_button.grid(row=0, column=0, padx=1, pady=1)
    del_button.grid(row=0, column=1, padx=1, pady=1)
    update_button.grid(row=0, column=2, padx=1, pady=1)
    clear2_button.grid(row=0, column=1, pady=1)

2、對各Button的功能實現(xiàn)

    # 主窗口方法
    # 獲取本地json數(shù)據(jù)
    json_data = []
    def get_json_data():
        try:
            with open('DB_data.json') as f:
                for line in f:
                    json_data.append(json.loads(line))
            return json_data
        except:
            info_text.insert(END, 'Error: 請檢查是否有添加的數(shù)據(jù)庫信息及文件婚脱!\n')
    
    # 退出主界面
    def quitcommand():
        root.quit()
        
    # 清空語句  
    def clear_input1():
        input_text.delete('0.0', END)
    
    # 清空信息
    def clear_input2():
        info_text.delete('0.0', END)
    
    # 刪除listbox中選中的數(shù)據(jù)庫信息最盅,以及本地數(shù)據(jù)庫信息文件的更改
    def del_db():
        index = db_list.curselection()[0]
        db_list.delete(index)
        with open('DB_data.json', 'r') as f:
            dataList = f.readlines()
            del(dataList[index])
        with open('DB_data.json', 'w') as f_w:
            for line in dataList:
                f_w.write(line)
    
    # 獲取json文件進行信息的更新
    def update_db_info():
        get_json_data()
        if not db_list.size():
            for i in range(len(json_data)):
                string = '第' + str(i+1) + '個數(shù)據(jù)庫' + '  ------  ' + 'DBname:  ' + json_data[i]['DBname'] + '  ------  ' +'Port:  ' + json_data[i]['port'] + '\n'
                db_list.insert(END, string)
        
    # 獲取json文件數(shù)據(jù)庫的信息,連接起惕,執(zhí)行語句,關閉連接
    def exe_input():
        get_json_data()
        for data in json_data:
            sql = input_text.get('0.0', END)
            try:
                conn = pymysql.connect(host=data['host'], user=data['user'], password=data['password'], port=int(data['port']), db=data['DBname'], charset=data['charset'])
                cursor = conn.cursor()
                cursor.execute(sql)
                conn.commit()
                info_text.insert(END, '操作完成')
            except Exception as e:
                conn.rollback()
                error_info = ('發(fā)生錯誤:' + str(e) + '\n')
                info_text.insert(END, error_info)
            finally:
                cursor.close()
                conn.close()

這里我們需要了解Python操作數(shù)據(jù)庫的方法咏删,以及文件操作的知識惹想、json的基本使用,因此我們還要import相應的包
PS:
python 2.7 使用 MySQLdb 進行數(shù)據(jù)庫操作
python 3.x 使用 pymysql 進行數(shù)據(jù)庫操作

3督函、添加界面實現(xiàn)

    # 創(chuàng)建添加二級窗口
    def create_add_frame():
        # 二級窗口方法
        def cancelCommand():
            add.destroy()
        
        def confirmCommand():
            data = {'host':host_entry.get(), 'user':user_entry.get(), 'password':ps_entry.get(), 'port':port_entry.get(), 'DBname':db_entry.get(), 'charset':charset_entry.get()}
            count = 0
            for v in data.values():
                if v != '':
                    count += 1
            if count == 6:
                with open('DB_data.json', 'a', encoding='utf-8') as f:
                    json.dump(data, f)
                    f.writelines('\n')
                    messagebox.showinfo('已完成', '數(shù)據(jù)庫信息已添加嘀粱!保存的數(shù)據(jù)將清空,請點擊更新鍵更新辰狡!')
                    db_list.delete(0,END)
                    add.destroy()
            else:
                messagebox.showinfo('提示', '請將6個參數(shù)填寫完整锋叨!')
        
        add = Toplevel() 
        add.title('添加新的數(shù)據(jù)庫')
        add.resizable(0, 0)
        add.wm_attributes('-topmost',1)  # 將add窗口置于root前
        
        # Label
        label_width = 20
        label_height = 1
        host_label =    Label(add, text='Host:', width=label_width, height=label_height)
        user_label =    Label(add, text='User:', width=label_width, height=label_height)
        ps_label =      Label(add, text='Password:', width=label_width, height=label_height)
        port_label =    Label(add, text='Port:', width=label_width, height=label_height)
        db_label =      Label(add, text='DBname:', width=label_width, height=label_height)
        charset_label = Label(add, text='Charset:', width=label_width, height=label_height)
        
        # Entry
        entry_width = 30
        host_entry =    Entry(add, width=entry_width, bd=3)
        user_entry =    Entry(add, width=entry_width, bd=3)
        ps_entry =      Entry(add, width=entry_width, bd=3)
        port_entry =    Entry(add, width=entry_width, bd=3)
        db_entry =      Entry(add, width=entry_width, bd=3)
        charset_entry = Entry(add, width=entry_width, bd=3)
        host_entry.focus()
        charset_entry.insert(END, 'utf8')
        
        # Button
        bt_width = 10
        bt_height = 2
        confirm_button = Button(add, text='確認', width=bt_width, height=bt_height, foreground='blue', command=confirmCommand)
        cancel_button =  Button(add, text='取消', width=bt_width, height=bt_height, foreground='blue', command=cancelCommand)
        
        # 窗口布局
        host_label.grid(row=0, column=0)
        user_label.grid(row=1, column=0)
        ps_label.grid(row=2, column=0)
        port_label.grid(row=3, column=0)
        db_label.grid(row=4, column=0)
        charset_label.grid(row=5, column=0)
        
        host_entry.grid(row=0, column=1)
        user_entry.grid(row=1, column=1)
        ps_entry.grid(row=2, column=1)
        port_entry.grid(row=3, column=1)
        db_entry.grid(row=4, column=1)
        charset_entry.grid(row=5, column=1)
        
        confirm_button.grid(row=6, column=0)
        cancel_button.grid(row=6, column=1)
        

添加界面會出現(xiàn)messagebox的使用,需要import宛篇,各功能都測試過使用正常娃磺,出現(xiàn)的BUG基本不影響使用,編碼時間2天完成叫倍,以后如有時間偷卧,將對此工具進行改進

各部分代碼全都展示完整,如果對pymysql和json的基本操作不熟吆倦,可以繼續(xù)往下看听诸,對代碼中細節(jié)有疑議或有更好方法的、需要源碼練習的蚕泽,請留言晌梨,相信我們會交談甚歡 φ(≧ω≦*)

1、pymysql的基本使用

import pymysql

# 創(chuàng)建連接,除了port是int類型仔蝌,其他都是str類型
conn = pymysql.connect(host=localhost, user=root, password='123456', port=3306, db=spiders, charset='utf8')

# sql語句
sql = 'SELECT acctid, money FROM bank'
    
try:
    # 創(chuàng)建游標
    cursor = conn.cursor()

    # 執(zhí)行sql語句
    cursor.execute(sql)

    # 對于增刪改操作泛领,需要此方法傳遞數(shù)據(jù)變化
    conn.commit()
except:
    # 如果執(zhí)行出錯,需要對數(shù)據(jù)回滾掌逛,回復原樣
    conn.rollback()
finally:
    # 關閉數(shù)據(jù)庫連接师逸,否則占用后臺資源
    cursor.close()
    conn.close()

2、json的基本用法

json雖然易用豆混,但由于第一次使用篓像,還是踩了不少坑

剛開始我是這樣保存數(shù)據(jù)的

with open('x.json', 'a', encoding='utf-8') as f:
        json.dump(data, f, indent=4)

利用文本形式打開,是這樣

{
    'a':'a',
    'b':'b'
}

2個數(shù)據(jù)時

{
    'a':'a',
    'b':'b'
}{
    'c':'c'.
    'd':'d'
}

是不是看著很整齊? 這都是indent=4的功勞

取出數(shù)據(jù)

with open('x.json', 'r', encoding='utf-8') as f:
    json.load(f)

你會發(fā)現(xiàn)皿伺,x.json中只有一個數(shù)據(jù)時员辩,運行良好,不會報錯鸵鸥,但存在多個時奠滑,就會出現(xiàn) extra data 的報錯

json進行文件操作有4個方法
1、dump()
2妒穴、dumps()
3宋税、load()
4、loads()

有什么區(qū)別嗎讼油?
1杰赛、dump() 將dict轉為str形式,并保存到文件中
2矮台、dumps() 將dict轉為str形式
3乏屯、load() 將str轉為dict形式,并從文件中取出
4瘦赫、loads() 將str轉為dict形式

使用dumps
a = {"123":"123"}
json.dumps(a) ——> '{"123":"123"}'

使用loads
b = '{"123":"123"}'
json.loads(b) ——> {"123":"123"}

所以當json文件存在多個數(shù)據(jù)時辰晕,它無法進行轉換,你可以簡單認為json.load()只能對只擁有一個數(shù)據(jù)的json文件進行處理确虱,那存在多個數(shù)據(jù)json文件就無法操作了含友?聰明的你已經(jīng)想到先對數(shù)據(jù)擇行分別取出,并分別進行轉換

但這樣的你要怎么分行處理呢蝉娜?

{
    'a':'a',
    'b':'b'
}{
    'c':'c'.
    'd':'d'
}

第一行就一個 唱较?

這樣格式化的數(shù)據(jù)是因為我們設置了indent=4,如果我們沒有設置這樣的參數(shù)召川,實際的保存效果是這樣的:

{"host": "localhost", "user": "root", "password": "123456", "port": "3306", "DBname": "spiders", "charset": "utf8"}

因此南缓,當我們需要存取多個json數(shù)據(jù)時,一定不要設置indent參數(shù)荧呐,并且在存入時加入\n進行分行

所以最后的獲取函數(shù)應該這樣寫

data = []
with open('x.json') as f:
    for line in f:
        data.append(json.loads(line))

Thank You For Watching...

小知識:如果想運行時想不出現(xiàn)cmd窗口汉形,可以將文件名x.py改成x.pyw哦

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末纸镊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子概疆,更是在濱河造成了極大的恐慌逗威,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岔冀,死亡現(xiàn)場離奇詭異凯旭,居然都是意外死亡,警方通過查閱死者的電腦和手機使套,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門罐呼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人侦高,你說我怎么就攤上這事嫉柴。” “怎么了奉呛?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵计螺,是天一觀的道長。 經(jīng)常有香客問我瞧壮,道長登馒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任咆槽,我火速辦了婚禮谊娇,結果婚禮上,老公的妹妹穿的比我還像新娘罗晕。我一直安慰自己,他們只是感情好赠堵,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布小渊。 她就那樣靜靜地躺著,像睡著了一般茫叭。 火紅的嫁衣襯著肌膚如雪酬屉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天揍愁,我揣著相機與錄音呐萨,去河邊找鬼。 笑死莽囤,一個胖子當著我的面吹牛谬擦,可吹牛的內容都是我干的。 我是一名探鬼主播朽缎,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼惨远,長吁一口氣:“原來是場噩夢啊……” “哼谜悟!你這毒婦竟也來了?” 一聲冷哼從身側響起北秽,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤葡幸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后贺氓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔚叨,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年辙培,在試婚紗的時候發(fā)現(xiàn)自己被綠了蔑水。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡虏冻,死狀恐怖肤粱,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情厨相,我是刑警寧澤领曼,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蛮穿,受9級特大地震影響庶骄,放射性物質發(fā)生泄漏。R本人自食惡果不足惜践磅,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一单刁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧府适,春花似錦羔飞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至疟暖,卻和暖如春卡儒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俐巴。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工骨望, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人欣舵。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓擎鸠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親缘圈。 傳聞我的和親對象是個殘疾皇子糠亩,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內容