問題描述:時間過得真快,一眨眼又一個月過去,2022又過去大半,7月的尾巴,終於稍微做出來點 東西,本人也不是開發,也是在不斷學習的一枚小白。這次使用tkinter制作了一個mysql的巡檢工具,使用圖形化操作,邊學邊操作,一路踩坑,寫的不好,但是能交出來一個東西,學習的過程中加深了對class的理解,學習了tkinter布局,如何連接數據庫等等。
python:Python 3.8.1
數據庫對象:MySQL
過程中遇到的問題
1.因為做的是數據庫巡檢系統,所以登錄的賬號往往是權限較大的比如root,然後如何去校驗root賬號,跟正常的管理系統不一樣,不是創建好用戶和密碼表,然後去比對。root是存放在數據庫系統中的,沒辦法去校驗root的用戶和密碼。這裡的root是作為參數傳進來的,所以如何去比對權限較大的用戶呢?
2.顯示頁面如何去加載數據庫中的查詢結果呢?按理說應該跟簡單,取得數據庫查詢的返回值,然後加載在頁面中。但最後這個顯示結果還不是很理想
3.數據庫登錄的時候如何返回mysql連接給的報錯值,如果只設置判斷是否登錄成功失敗很簡單,但是在返回mysql報錯值的時候如何返回給前台呢
登錄類
class Application(Frame):
username = ''
password = ''
ip = ''
port = '' def __init__(self,master=None):
super().__init__(master)
self.master = master
self.pack()
self.createWidget() def createWidget(self): #創建組件容器 page = Frame(self)
page.pack() self.usernameGet = StringVar()
self.usernameGet.set('root')
self.passwordGet = StringVar()
self.passwordGet.set('zabbix.9.31')
self.ipGet = StringVar()
self.ipGet.set('192.168.163.21')
self.portGet = StringVar() #這裡如果設置IntVar,GUI上會顯示0,整數可以為0,不能是空
self.portGet.set('33306') Label(page).grid(row=0,column=0)
Label(page,text='賬戶:').grid(row=1,column=1)
Entry(page,textvariable=self.usernameGet).grid(row=1,column=2)
Label(page,text='密碼:').grid(row=2,column=1)
Entry(page,textvariable=self.passwordGet,show='*').grid(row=2,column=2)
Label(page,text='IP地址:').grid(row=3,column=1)
Entry(page,textvariable=self.ipGet).grid(row=3,column=2)
Label(page,text='端口:').grid(row=4,column=1)
Entry(page,textvariable=self.portGet).grid(row=4,column=2) Button(page,text='登錄',command=self.login_check).grid(row=5,column=1,pady=10)
Button(page,text='退出',command=page.quit).grid(row=5,column=2)
def login_check(self): #設置登錄退出按鈕
i = self.ipGet.get()
p = int(self.portGet.get())
u = self.usernameGet.get()
pa = self.passwordGet.get()
db_name = 'mysql' #實例化Mysql類
mysqlLogin = Mysql(i,p,u,pa,db_name) #這裡不能用mysqllogin對象做布爾值判斷,只要輸入正確,他的布爾值一直是true
results = mysqlLogin.select('select @@version')
print(bool(mysqlLogin));print(bool(results))
if results:
messagebox.showinfo('提示', '連接成功,正在為您生成巡檢報告')
# print(type(i),type(p),type(u),type(pa))
self.destroy()
MainPage(root)
mysqlLogin.show()
數據庫連接類
class Mysql(object):
# mysql 端口號,注意:必須是int類型
def __init__(self, host, port, user, passwd, db_name):
self.host = host
self.user = user
self.passwd = passwd
self.port = port
self.db_name = db_name def select(self, sql):
"""
執行sql命令
:param sql: sql語句
:return: 元祖
"""
try:
conn = pymysql.connect(
host=self.host,
user=self.user,
passwd=self.passwd,
port=self.port,
database=self.db_name,
charset='utf8',
#cursorclass=pymysql.cursors.DictCursor
)
cur = conn.cursor() # 創建游標
# conn.cursor()
cur.execute(sql) # 執行sql命令
#print(type(cur.execute(sql)))
res = cur.fetchall() # 獲取執行的返回結果
#print(type(res))
cur.close()
conn.close()
# print(res)
return res
except Exception as e:
messagebox.showerror('提示',e)
return False def show(self):
sql1 = "show global variables"
# sql2 = "show master status;"
# sql3 = "SELECT table_schema,SUM((AVG_ROW_LENGTH*TABLE_ROWS+INDEX_LENGTH))/1024 AS total_KB FROM information_schema.TABLES GROUP BY table_schema ORDER BY total_KB DESC ;" res1 = dict(self.select(sql1))
# res2 = self.select(sql2)
# res3 = self.select(sql3)
filename = r"D:\{}".format('mysql_check.txt')
with open(filename, mode='w', encoding='utf-8') as f:
# 檢查MySQL版本
#print("\033[1;32m當前數據庫的版本是:\033[0m" + res1['version'])
f.write("當前數據庫的版本是:" + res1['version'] + "\n") f.write("當前數據庫的version_comment是:" + res1['version_comment'] + "\n")
f.write("當前數據庫的version_compile_machine是:" + res1['version_compile_machine'] + "\n")
f.write("當前數據庫的version_compile_os是:" + res1['version_compile_os'] + "\n")
f.write("當前數據庫的version_compile_zlib是:" + res1['version_compile_zlib'] + "\n")
f.write("當前數據庫的sql_mode是:" + res1['sql_mode'] + "\n") # 檢查MySQL端口
#print("\033[1;35m當前數據庫的端口是:\033[0m" + res1['port'])
f.write("當前數據庫的端口是:" + res1['port'] + "\n")
# 檢查server_id
#print("\033[1;32m當前數據庫的server_id是:\033[0m" + res1['server_id'])
f.write("當前數據庫的server_id是:" + res1['server_id'] + "\n")
# 檢查basedir目錄
#print("\033[1;32m當前數據庫的basedir在:\033[0m" + res1['basedir'])
f.write("當前數據庫的basedir在:" + res1['basedir'] + "\n")
# 檢查datadir目錄
#print("\033[1;35m當前數據庫的datadir在:\033[0m" + res1['datadir'])
f.write("當前數據庫的datadir在:" + res1['datadir'] + "\n")
# 檢查tmpdir目錄
#print("\033[1;32m當前數據庫的tmpdir在:\033[0m" + res1['tmpdir'])
f.write("當前數據庫的tmpdir在:" + res1['tmpdir'] + "\n") #pid_file
f.write("當前數據庫的pid_file在:" + res1['pid_file'] + "\n")
#optimizer_switch
f.write("當前數據庫的optimizer_switch:" + res1['optimizer_switch'] + "\n")
#mysqlx_socket
f.write("mysqlx_socket:" + res1['mysqlx_socket'] + "\n")
#log_bin_basename
f.write("當前數據庫的log_bin_basename在:" + res1['log_bin_basename'] + "\n")
#log_error
f.write("當前數據庫的log_error在:" + res1['log_error'] + "\n")
#slow_query_log_file
f.write("當前數據庫的slow_query_log_file在:" + res1['slow_query_log_file'] + "\n")
class MainPage:
def __init__(self,master: tk.Tk):
self.root = master
self.root.title('數據庫巡檢系統')
self.root.geometry('600x400')
self.create_page()
def create_page(self):
self.about_frame = AboutFrame(self.root) #調用views中的aboutframe類,顯示關於的信息
# tk.Label(self.about_frame,text = '關於作品:數據庫巡檢系統').pack()
# tk.Label(self.about_frame,text = '關於作者:我愛睡蓮').pack()
# tk.Label(self.about_frame,text = '版權所有:https://www.cnblogs.com/houzhiheng/').pack() self.check_frame = CheckFrame(self.root) menubar = tk.Menu(self.root)
menubar.add_command(label='巡檢結果',command=self.show_check)
menubar.add_command(label='關於',command=self.show_about)
self.root['menu'] = menubar def show_check(self):
self.check_frame.pack()
self.about_frame.pack_forget() #選擇性遺忘其他加載過的頁面,要不然都會加載在頁面當中 def show_about(self):
self.about_frame.pack()
self.check_frame.pack_forget()
顯示關於部分類
class AboutFrame(tk.Frame):
def __init__(self,root):
super().__init__(root)
tk.Label(self, text='Production:數據庫巡檢系統').pack()
tk.Label(self, text='Author:我愛睡蓮').pack()
tk.Label(self, text='Version:1.0').pack()
tk.Label(self, text='@Copyright:https://www.cnblogs.com/houzhiheng/').pack()
顯示數據庫巡檢結果類
class CheckFrame(tk.Frame):
def __init__(self,root):
super().__init__(root)
# tk.Label(self, text='巡檢結果').pack()
self.table_view = tk.Frame()
self.table_view.pack() self.create_page() tk.Button(self,text='保存文件',command=self.save_data_frame).pack(anchor=tk.E,pady=5) def create_page(self):
# self.tree_view = ttk.Treeview(self,show='headings')
# columns = ("check_results")
# columns_values = ("數據庫巡檢報告")
# top = Tk() # 設置窗口
# sb = Scrollbar(top) # 設置窗口滾動條
# sb.pack(side=RIGHT, fill=) # 設置窗口滾動條位置
# self.sb = Scrollbar()
# self.sb.pack(side=RIGHT,fill= Y)
# self.tree_view = ttk.Treeview(self,show='headings',columns=columns)
# self.tree_view.column('check_results',width=500,anchor='center')
# self.tree_view.heading('check_results',text=columns_values)
# self.tree_view.pack(fill=tk.BOTH,expand=True)
# self.show_data_frame() with open(r'D:\mysql_check.txt', 'r', encoding='utf-8') as f:
lines2 = [l.split() for l in f.readlines() if l.strip()]
# 滾動條初始化(scrollBar為垂直滾動條,scrollBarx為水平滾動條)
scrollBar = Scrollbar(self)
scrollBarx = Scrollbar(self, orient=HORIZONTAL)
# 靠右,充滿Y軸
scrollBar.pack(side=RIGHT, fill=Y)
# 靠下,充滿X軸
scrollBarx.pack(side=BOTTOM, fill=X)
lb = Text(self, width=100, height=25,)
lb.pack()
# db = Mysql('192.168.163.21', 33306, 'root', 'zabbix.9.31', 'mysql')
# res = db.show() textvar = "1:{} \n2:{}\n3:{}\n4:{}\n5:{}\n6:{}\n7:{}\n8:{}\n9:{}\n10:{}\n11:{}\n12:{}\n13:{}\n14:{}\n15:{}"\
.format(lines2[0],lines2[1],lines2[2],lines2[3],lines2[4],lines2[5],lines2[6],lines2[7],lines2[8],lines2[9],lines2[10],lines2[11],lines2[12],lines2[13],lines2[14],lines2[15],lines2[16])
lb.insert('insert', textvar + '\n')
lb.update()
# 而當用戶操縱滾動條的時候,自動調用 Treeview 組件的 yview()與xview() 方法
# 即滾動條與頁面內容的位置同步
scrollBar.config(command=lb.yview)
scrollBarx.config(command=lb.xview) def show_data_frame(self): #把查詢的內容輸出到屏幕上來
pass
def save_data_frame(self):
messagebox.showinfo('提示','您的文件已保存在D:\mysql_check.txt中!')
問題處理:
1.如何去對比root登錄是否成功呢,從上面代碼可以看到,我沒法去直接登錄數據庫去校驗用戶名和密碼,但是我可以讓用戶名登錄成功去執行命令來判斷是否登錄成功,如果root登陸並且成功執行命令,我就返回一個結果為TRUE,如果執行失敗,就返回一個結果為FALSE,這條命令是去查詢數據庫自身版本得到,任何用戶都可以執行
2.在屏幕上輸出巡檢的結果,本來取得數據庫返回值然後給屏幕上就可以了,但是我的views.py調用class MySQL類失敗,所以最後直接把查詢結果保存在了文件中,前台輸出的時候打開文件,然後調整文件格式就輸出了,敗筆啊這一步
3.將mysql連接返回的報錯做成異常處理即可,只不過當時做的時候邏輯有一點問題一直沒顯示成功
結論收獲:
本來是想做一個全套的數據庫巡檢GUI系統,桌面版本的已經做好了,但是沒有到光做一個GUI+mysql版本的就花費了兩周時間了,不過這個大體結構成型,後邊如果想做應該會簡單些。這次更加深刻了解了面向對象,上學沒學好,畢業了都得補回來
一.python gui(圖形化)模塊介紹: Tkinter :是python最簡單的圖形化模塊,總共只有14種組建 Pyqt :是python最復雜也是使用最廣泛的圖形化 Wx ...
HeidiSQL 是一款用於簡單化的 MySQL server和數據庫管理的圖形化界面.該軟件同意你浏覽你的數據庫,管理表,浏覽和編輯記錄,管理用戶權限等等.此外,你能夠從文本文件導入數據,執行 SQ ...
黑馬程序員:Java基礎總結 GUI圖形化界面 ASP.Net+Android+IO開發 . .Net培訓 .期待與您交流! GUI(Graphical User Interface)圖形化界 ...
[.net 面向對象程序設計進階] (26) 團隊開發利器(五)分布式版本控制系統Git——圖形化Git客戶端工具TortoiseGit 讀前必備: 接上篇: 分布式版本控制系統Git——使用GitS ...
Atiti qq空間破解(3)------------gui圖形化通用cli執行器atiuse 結構:::命令行+以及反饋log框1 cli_guiUI/index.htm1 /AtiPlatf_c ...
追加一個zookeeper圖形化的客戶端工具: 1.zookeeper圖像化客戶端工具的下載地址:https://issues.apache.org/jira/secure/attachment/12 ...
在上一章裡,重點分享了命令行SQL分析工具的使用方法.在本章將重點分享PL/SQL的SQL分析工具. 一.如何打開PL/SQL執行計劃 開啟PL/SQL這工具,推薦如下方法: 點擊 ...
追加一個zookeeper圖形化的客戶端工具: 1.zookeeper圖像化客戶端工具的下載地址:https://issues.apache.org/jira/secure/attachment/12 ...
matplotlib是python中常用的數據圖形化工具,用法跟matlab有點相似.調用簡單,功能強大.在Windows下可以通過命令行 pip install matplotlib 來進行安裝. ...
MYSQL官網也推出了針對Linux的圖形化的連接工具-MySQL Workbench.MySQL Workbench不僅僅是一個簡單的MySQL客戶端.簡而言之,Workbench是一個跨平台的 ( ...
在C#.NET的開發中,事件是經常接觸到的概念,比如為按鈕添加點擊事件,並寫入點擊按鈕觸發事件要運行的代碼.不管是ASP.NET還是WinForm等各種形式的應用程序,最經常是為系統生成的事件寫具體代 ...
/*"水災巡視問題"模擬退火算法.這是一個推銷員問題,本題有53個點,所有可能性大約為exp(53),目前沒有好方法求出精確解,既然求不出精確解,我們使用模擬退火法求出一個較優解, ...
前面的話 events模塊是node的核心模塊,幾乎所有常用的node模塊都繼承了events模塊,比如http.fs等.本文將詳細介紹nodeJS中的事件機制 EventEmitter 多數 Nod ...
APP開發中經常會遇到這種需求,需要檢查當前的APP是不是可見的,比如,如果是可見的就維持一個socket長連接,如果切到後台不可見了,就斷開這個連接.Android本來並不允許APP去監聽home鍵 ...
一.PCA簡介 1. 相關背景 在許多領域的研究與應用中,往往需要對反映事物的多個變量進行大量的觀測,收集大量數據以便進行分析尋找規律.多變量大樣本無疑會為研究和應用提供了豐富的信息,但也在一定程度上 ...
一.Connections 連接函數接口libvirt.open(name); //可讀寫方式連接上QEMU 參數說明: name:連接名稱libvirt.openAuth(uri, auth, fl ...
圓滑:主題下載對應主題js引入後注入對應名稱參數方可使用主題 初始化:tab點擊的時候初始化圖表涉及到tab切換到的需要延遲加載否則默認寬度為100px 1.創建macarons.js文件 2.頁面添 ...
hdoj 1004題目大概講的是,將輸入的字符串根據輸入次數多少,輸出出現次數最多的字符串. 題目邏輯很簡單,就是需要選擇相應的數據結構,看了別人提交的discuss,明顯發現可以使用多種數據結構解這 ...
http://acm.zzuli.edu.cn/problem.php?id=1783 1783: 簡單的求和 Time Limit: 1 Sec Memory Limit: 128 MBSubmi ...
CSS:層疊樣式表(英文全稱:Cascading Style Sheets) 後綴名:css 標志 style 對網頁中元素位置的排版進行像素級精 ...