1、顯示數(shù)據(jù)庫(kù)內(nèi)容。
2、修改數(shù)據(jù)庫(kù)內(nèi)容。
3、表格控件指定滑塊位置。
4、自定義右鍵菜單。
使用環(huán)境:python3.7 + Mysql5 +PyQt5
針對(duì)人群:初學(xué)者或有資料查閱需求者,資深人士勿噴,敬請(qǐng)?zhí)岢鰧氋F意見,本人虛心接受。
前期準(zhǔn)備:
1、創(chuàng)建軟件界面
2、與數(shù)據(jù)庫(kù)建立連接
1、創(chuàng)建軟件界面:
上圖為使用PyQt5相關(guān)模塊創(chuàng)建的工程造價(jià)系統(tǒng)界面,使用的模塊及功能:
1、QMainWindow模塊:繪制帶菜單、工具欄、狀態(tài)欄的整體框架。
2、QTreeWidget模塊:繪制左側(cè)導(dǎo)航欄。
3、QTableWidgetItem模塊:繪制中間用于顯示數(shù)據(jù)的表格。
4、QComboBox, QPushButton模塊:繪制下拉框、按鈕控件。
5、QSplitter模塊:設(shè)置各種控件的擺放組合方式,可鼠標(biāo)拖動(dòng)調(diào)整窗口大小。
6、QMessageBox模塊:設(shè)置交互彈框。
具體界面繪制過程不是本文重點(diǎn),暫不詳述。
2、與數(shù)據(jù)庫(kù)建立連接
要建立與數(shù)據(jù)庫(kù)的連接,首先得有具體的數(shù)據(jù)庫(kù),本案例在本機(jī)用mysql建立自己的數(shù)據(jù)庫(kù),然后再與軟件項(xiàng)目進(jìn)行連接。
2.1、自建數(shù)據(jù)庫(kù)
下載安裝好Mysql后,建議再裝一個(gè)可視化工具,我用的Navicat for Mysql,感覺不錯(cuò)。界面見下圖:
在這個(gè)工具界面下,可以很方便的創(chuàng)建修改數(shù)據(jù)表。有了工具后,接下來(lái)就是關(guān)鍵的填入數(shù)據(jù)。很多時(shí)候,客戶或者我們自己的數(shù)據(jù)是放在excel里的,我們可以通過Navicat 的導(dǎo)入向?qū)?,很方便的將excel數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫(kù):
跟著向?qū)?,只需?jiǎn)單幾步就可完成數(shù)據(jù)導(dǎo)入。
2.2、連接數(shù)據(jù)庫(kù)
導(dǎo)入pymysql庫(kù),將庫(kù)的連接等功能寫入自建的類。本案通過讀取.cfg配置文件(有關(guān)配置文件的知識(shí),可參見python開發(fā)項(xiàng)目,不得不了解的.cfg配置文件),獲得連接庫(kù)需用到的5個(gè)參數(shù),在_init_初始類屬性時(shí),建立連接,代碼如下:
import pymysql
from configparser import ConfigParser
class MysqlDb():
def __init__(self):
self.cp = ConfigParser()
self.cp.read('source/sql_config.cfg')
host = self.cp.get('sql_connect', 'host')
port = int(self.cp.get('sql_connect', 'port'))
user = self.cp.get('sql_connect', 'user')
passwd = self.cp.get('sql_connect', 'passwd')
db = self.cp.get('sql_connect', 'db')
self.conn = pymysql.connect(host=host,
port=port,
user=user,
passwd=passwd,
db=db)
self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
其中,sql_config.cfg文件內(nèi)容為:
若不用配置文件,直接把5個(gè)參數(shù)寫在程序里也可以,代碼如下,貌似更簡(jiǎn)單:
class MysqlDb():
def __init__(self):
self.conn = pymysql.connect(host=‘127.0.0.1’,
port=3306,
user=‘root’,
passwd=‘771222’,
db=‘1’)
self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
一、顯示數(shù)據(jù)庫(kù)內(nèi)容
功能:在軟件界面,點(diǎn)擊左側(cè)導(dǎo)航欄,找到數(shù)據(jù)庫(kù)中與展開項(xiàng)對(duì)應(yīng)的表,將數(shù)據(jù)顯示在中間表格里。若目標(biāo)表不存在,提示創(chuàng)建。
實(shí)現(xiàn)步驟:
創(chuàng)建導(dǎo)航欄; → 點(diǎn)擊導(dǎo)航欄,獲取表名; → 查詢數(shù)據(jù)庫(kù),找到表,顯示內(nèi)容
具體過程:
1、用樹形控件創(chuàng)建導(dǎo)航欄,數(shù)據(jù)來(lái)源為數(shù)據(jù)庫(kù)
數(shù)據(jù)庫(kù)里導(dǎo)航欄數(shù)據(jù)源樣式為:
用代碼手動(dòng)逐條輸入是不可接受的,根據(jù)第一列數(shù)據(jù)長(zhǎng)度特點(diǎn),采用下面的批量創(chuàng)建方式,其中fl為傳遞的參數(shù),意思是“路基”或者其他專業(yè)。
def set_tree(self, fl):
qd_lj = MysqlDb().select_db('SELECT * FROM 清單' + fl) # 通過自建的Mysqlbd類的select_db函數(shù),得到數(shù)據(jù)庫(kù)里的目標(biāo)表
root = QTreeWidgetItem(self.tree)
root.setText(0, fl)
root.setIcon(0, QIcon(r'source\3.png'))
for i in range(0, len(qd_lj)):
bm = qd_lj[i]['編碼']
mc = qd_lj[i]['名稱']
if (len(bm) == 4):
root1 = QTreeWidgetItem(root)
root1.setText(0, mc)
root1.setText(1, bm)
elif (len(bm) == 7):
root2 = QTreeWidgetItem(root1)
root2.setText(0, mc)
root2.setText(1, bm)
elif (len(bm) == 10):
root3 = QTreeWidgetItem(root2)
root3.setText(0, mc)
root3.setText(1, bm)
elif (len(bm) == 13):
root4 = QTreeWidgetItem(root3)
root4.setText(0, mc)
root4.setText(1, bm)
elif (len(bm) == 16):
root5 = QTreeWidgetItem(root4)
root5.setText(0, mc)
root5.setText(1, bm)
elif (len(bm) == 19):
root6 = QTreeWidgetItem(root5)
root6.setText(0, mc)
root6.setText(1, bm)
elif (len(bm) == 22):
root7 = QTreeWidgetItem(root6)
root7.setText(0, mc)
root7.setText(1, bm)
else:
pass
self.tree.expandAll() # 設(shè)置樹形構(gòu)件全部展開
self.item = root # 自定義設(shè)置初始選中根條目
2、設(shè)置點(diǎn)擊樹形控件條目的信號(hào)槽函數(shù),將數(shù)據(jù)庫(kù)表內(nèi)容提取后顯示在表格控件。
self.tree.itemClicked.connect(self.showtreesql)
設(shè)置左鍵單擊導(dǎo)航欄時(shí),觸發(fā)函數(shù)showtreesql()。具體獲取數(shù)據(jù)功能在函數(shù)里設(shè)置。
def showtreesql(self, item): # 單擊樹形節(jié)點(diǎn),將數(shù)據(jù)庫(kù)內(nèi)容顯示在表里
self.inputtable.clearContents() #清空中間的表格控件
self.inputtable.setRowCount(0) # 初始表格控件
self.item = item # 單擊導(dǎo)航欄時(shí),信號(hào)槽自動(dòng)帶當(dāng)前點(diǎn)擊節(jié)點(diǎn)信息參數(shù)item
if not item.child(0): # 判斷如果該節(jié)點(diǎn)沒有子節(jié)點(diǎn),即單擊的為最底層節(jié)點(diǎn),非子節(jié)點(diǎn)無(wú)對(duì)應(yīng)表格
self.decxcomb3.setDisabled(False)
self.select_item = "n" + item.text(1).replace('-', '') # 根據(jù)該節(jié)點(diǎn)編碼,得到對(duì)應(yīng)表格名稱
if self.decxcomb3.findText(self.select_item) == -1:
self.decxcomb3.addItem(self.select_item)
self.decxcomb3.setCurrentText(self.select_item) # 將表格名稱顯示在下拉框控件里
if self.table_exists(MysqlDb(),
self.select_item): # 查詢數(shù)據(jù)庫(kù),判斷是否存在對(duì)應(yīng)的表,
self.inputtable.setRowCount(1)
self.sql_to_input(self.select_item, self.inputtable) #如果存在表,查詢數(shù)據(jù)庫(kù),將數(shù)據(jù)讀取到表格
else:
# self.decxcomb3.isEnabled()
self.decxcomb3.setDisabled(True)
3、讀取數(shù)據(jù)庫(kù)內(nèi)容到表格的功能函數(shù)代碼:
def sql_to_input(self, sql_tabel, inputtable):
data = MysqlDb().select_db('SELECT * FROM ' + sql_tabel)
if data:
inputtable.setRowCount(len(data))
for i in range(len(data)):
inputtable.setItem(i, 0, QTableWidgetItem(data[i]['定額編號(hào)']))
inputtable.setItem(i, 1, QTableWidgetItem(data[i]['定額名稱']))
inputtable.setItem(i, 2, QTableWidgetItem(data[i]['單位']))
inputtable.setItem(i, 3, QTableWidgetItem(data[i]['數(shù)量']))
# print('數(shù)據(jù)庫(kù)寫入已完成”')
else:
# print('源表為空表,不執(zhí)行寫入操作')
pass
判斷數(shù)據(jù)庫(kù)是否存在某表的函數(shù)塊:
def table_exists(self, sql, table_name): # 這個(gè)函數(shù)用來(lái)判斷數(shù)據(jù)庫(kù)是否含某表
tables = sql.select_db('SHOW TABLES') # 得到數(shù)據(jù)庫(kù)里的所有表名,
tabels_list = []
for i in tables:
n = i['Tables_in_1']
tabels_list.append(n)
if table_name in tabels_list:
return 1
else:
return 0
4、左鍵雙擊導(dǎo)航欄時(shí),觸發(fā)信號(hào)槽,當(dāng)不存在目標(biāo)表時(shí),提示創(chuàng)建新表:
def edittreesql(self, item): # 雙擊樹形節(jié)點(diǎn),將新建數(shù)據(jù)庫(kù)表
if not item.child(0): # 判斷該節(jié)點(diǎn)沒有子節(jié)點(diǎn)
self.select_item = "n" + item.text(1).replace('-', '') # 記錄該節(jié)點(diǎn)編碼
self.decxcomb3.addItem(self.select_item)
self.decxcomb3.setCurrentText(self.select_item)
if self.table_exists(MysqlDb(), self.select_item): # 判斷是否存在本節(jié)點(diǎn)為名的表
# 判斷結(jié)果存在,將內(nèi)容顯示在表格控件里
self.inputtable.clearContents()
self.sql_to_input(self.select_item, self.inputtable)
else:
if QMessageBox.information(self, "創(chuàng)建定額表",
"即將為本清單創(chuàng)建定額輸入表:" + self.select_item,
QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
MysqlDb().biuldtabel(self.select_item) # 若沒有則在數(shù)據(jù)庫(kù)新建一個(gè)表,
self.inputtable.clearContents()
self.inputtable.setRowCount(1)
print('已創(chuàng)建表:', self.select_item)
二、修改數(shù)據(jù)庫(kù)內(nèi)容
1、設(shè)置保存按鈕
self.saveinput = QPushButton('保存到數(shù)據(jù)庫(kù)')
self.saveinput.clicked.connect(self.input_to_sql)
2、編寫保存按鈕點(diǎn)擊函數(shù)塊
def input_to_sql(self):
if self.decxcomb3.currentText():
MysqlDb().execute_db('DELETE FROM ' +
self.decxcomb3.currentText()) # 寫入數(shù)據(jù)庫(kù)前先清空原內(nèi)容
for i in range(self.inputtable.rowCount()):
v = []
for j in range(4):
if self.inputtable.item(i, j):
v.append(self.inputtable.item(i, j).text())
else:
v.append('')
insert_sql = 'INSERT INTO ' + self.decxcomb3.currentText(
) + " (定額編號(hào), 定額名稱, 單位, 數(shù)量) VALUES('" + v[0] + "', '" + v[
1] + "', '" + v[2] + "', '" + v[3] + "')"
MysqlDb().execute_db(insert_sql)
三、表格控件指定滑塊位置
設(shè)置下拉框選擇項(xiàng)目后,根據(jù)項(xiàng)目名讓中間下部的表格上下滑塊移動(dòng)至將當(dāng)前項(xiàng)目顯示在第一位:
設(shè)置信號(hào)槽:self.decxcomb2.currentTextChanged[str].connect(self.set_table2)
設(shè)置功能塊代碼:
def set_table2(self, fl):
for i in range(self.table2.rowCount()):
if self.table2.item(i, 0).text() == fl:
break
self.table2.verticalScrollBar().setValue(i)
四、自定義右鍵菜單
表格輸入時(shí),有時(shí)候難免存在需要插入行、刪除行的要求,最常見的就是下面的右鍵菜單處理了。
實(shí)現(xiàn)過程:
1)設(shè)置表格控件能響應(yīng)右鍵
self.inputtable.setContextMenuPolicy(Qt.CustomContextMenu)
2)設(shè)置右鍵信號(hào)槽函數(shù)
self.inputtable.customContextMenuRequested.connect(self.input_rightmenu)
def input_rightmenu(self): # 指定定額輸入表控件右鍵菜單
try:
self.contextMenu = QMenu()
self.actionA = self.contextMenu.addAction(u'刪除')
self.actionB = self.contextMenu.addAction(u'插入')
self.actionA.setIcon(QIcon(r"source\4.png"))
self.contextMenu.popup(QCursor.pos()) # 菜單顯示的位置
self.actionA.triggered.connect(self.deletcurrow)
self.actionB.triggered.connect(self.insertcurrow)
self.contextMenu.show()
except Exception as e:
print(e)
3)函數(shù)功能塊設(shè)置
def deletcurrow(self):
self.inputtable.removeRow(self.inputtable.currentRow())# 刪除當(dāng)前行
def insertcurrow(self):
self.inputtable.insertRow(self.inputtable.currentRow()) #在當(dāng)前行插入一行