在日常开发中,我们常常需要快速查看和操作SQLite数据库中的数据。虽然有许多现成的工具可以完成这一任务,但有时你可能想要一个更为简单、可定制的解决方案。在这篇博客中,我将带你一步步构建一个简单的SQLite数据库浏览器,它可以用来列出数据库中的表名、查看表的字段名、编写SQL语句并执行查询操作,并将结果展示在网格中。我们将使用 wxPython
来创建这个图形用户界面。
C:\pythoncode\new\sqliteanalysis.py
全部代码
import wx
import sqlite3
import wx.grid as gridlib
class SQLiteBrowser(wx.Frame):
def __init__(self, *args, **kw):
super(SQLiteBrowser, self).__init__(*args, **kw)
self.InitUI()
self.conn = None
def InitUI(self):
panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
self.btn_open = wx.Button(panel, label="Open Database")
self.btn_open.Bind(wx.EVT_BUTTON, self.OnOpen)
hbox1.Add(self.btn_open, flag=wx.LEFT, border=10)
vbox.Add(hbox1, flag=wx.EXPAND | wx.TOP | wx.BOTTOM, border=10)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
self.listbox1 = wx.ListBox(panel)
self.listbox1.Bind(wx.EVT_LISTBOX, self.OnTableSelected)
hbox2.Add(self.listbox1, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
self.listbox2 = wx.ListBox(panel)
self.listbox2.Bind(wx.EVT_LISTBOX, self.OnColumnSelected)
hbox2.Add(self.listbox2, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
vbox.Add(hbox2, proportion=1, flag=wx.EXPAND)
hbox3 = wx.BoxSizer(wx.HORIZONTAL)
self.text_ctrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
hbox3.Add(self.text_ctrl, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
self.btn_exec = wx.Button(panel, label="Execute SQL")
self.btn_exec.Bind(wx.EVT_BUTTON, self.OnExecuteSQL)
hbox3.Add(self.btn_exec, flag=wx.LEFT, border=10)
vbox.Add(hbox3, proportion=1, flag=wx.EXPAND)
hbox4 = wx.BoxSizer(wx.HORIZONTAL)
self.grid = gridlib.Grid(panel)
self.grid.CreateGrid(5, 5)
hbox4.Add(self.grid, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
vbox.Add(hbox4, proportion=3, flag=wx.EXPAND)
panel.SetSizer(vbox)
self.SetTitle('SQLite Browser')
self.Centre()
def OnOpen(self, event):
with wx.FileDialog(self, "Open SQLite file", wildcard="SQLite files (*.db)|*.db",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
path = fileDialog.GetPath()
self.conn = sqlite3.connect(path)
self.LoadTables()
def LoadTables(self):
if self.conn:
cursor = self.conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = [row[0] for row in cursor.fetchall()]
self.listbox1.Set(tables)
def OnTableSelected(self, event):
table_name = self.listbox1.GetStringSelection()
if self.conn:
cursor = self.conn.cursor()
cursor.execute(f"PRAGMA table_info({table_name})")
columns = [row[1] for row in cursor.fetchall()]
self.listbox2.Set(columns)
def OnColumnSelected(self, event):
column_name = self.listbox2.GetStringSelection()
current_text = self.text_ctrl.GetValue()
if current_text:
current_text += f", {column_name}"
else:
current_text = column_name
self.text_ctrl.SetValue(current_text)
def OnExecuteSQL(self, event):
sql_query = self.text_ctrl.GetValue()
if self.conn and sql_query.strip():
cursor = self.conn.cursor()
try:
cursor.execute(sql_query)
results = cursor.fetchall()
self.DisplayResults(results)
except sqlite3.Error as e:
wx.MessageBox(f"An error occurred: {e}", "Error", wx.OK | wx.ICON_ERROR)
def DisplayResults(self, results):
if results:
rows = len(results)
cols = len(results[0])
self.grid.ClearGrid()
if rows > self.grid.GetNumberRows():
self.grid.AppendRows(rows - self.grid.GetNumberRows())
if cols > self.grid.GetNumberCols():
self.grid.AppendCols(cols - self.grid.GetNumberCols())
for i, row in enumerate(results):
for j, value in enumerate(row):
self.grid.SetCellValue(i, j, str(value))
if __name__ == '__main__':
app = wx.App(False)
frame = SQLiteBrowser(None)
frame.Show(True)
app.MainLoop()
环境准备
在开始之前,你需要确保已安装以下Python库:
- wxPython:用于创建桌面应用的GUI库。
- sqlite3:Python自带的SQLite接口模块,用于与SQLite数据库进行交互。
如果你尚未安装 wxPython
,可以通过以下命令安装:
pip install wxPython
项目目标
我们将创建一个简单的应用程序,其主要功能包括:
- 选择SQLite数据库文件:通过文件选择对话框选择一个SQLite数据库文件,并与之建立连接。
- 列出表名:在左侧列表框中列出所选数据库的所有表名。
- 列出字段名:在中间列表框中列出所选表的所有字段名。
- 构建SQL查询:点击字段名,自动将其追加到查询输入框中。
- 执行SQL查询:点击执行按钮,运行输入框中的SQL查询语句,并将结果展示在网格中。
代码实现
以下是完整的Python代码,它实现了上述所有功能:
import wx
import sqlite3
import wx.grid as gridlib
class SQLiteBrowser(wx.Frame):
def __init__(self, *args, **kw):
super(SQLiteBrowser, self).__init__(*args, **kw)
self.InitUI()
self.conn = None
def InitUI(self):
panel = wx.Panel(self)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
self.btn_open = wx.Button(panel, label="Open Database")
self.btn_open.Bind(wx.EVT_BUTTON, self.OnOpen)
hbox1.Add(self.btn_open, flag=wx.LEFT, border=10)
vbox.Add(hbox1, flag=wx.EXPAND | wx.TOP | wx.BOTTOM, border=10)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
self.listbox1 = wx.ListBox(panel)
self.listbox1.Bind(wx.EVT_LISTBOX, self.OnTableSelected)
hbox2.Add(self.listbox1, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
self.listbox2 = wx.ListBox(panel)
self.listbox2.Bind(wx.EVT_LISTBOX, self.OnColumnSelected)
hbox2.Add(self.listbox2, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
vbox.Add(hbox2, proportion=1, flag=wx.EXPAND)
hbox3 = wx.BoxSizer(wx.HORIZONTAL)
self.text_ctrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
hbox3.Add(self.text_ctrl, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
self.btn_exec = wx.Button(panel, label="Execute SQL")
self.btn_exec.Bind(wx.EVT_BUTTON, self.OnExecuteSQL)
hbox3.Add(self.btn_exec, flag=wx.LEFT, border=10)
vbox.Add(hbox3, proportion=1, flag=wx.EXPAND)
hbox4 = wx.BoxSizer(wx.HORIZONTAL)
self.grid = gridlib.Grid(panel)
self.grid.CreateGrid(5, 5)
hbox4.Add(self.grid, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
vbox.Add(hbox4, proportion=3, flag=wx.EXPAND)
panel.SetSizer(vbox)
self.SetTitle('SQLite Browser')
self.Centre()
def OnOpen(self, event):
with wx.FileDialog(self, "Open SQLite file", wildcard="SQLite files (*.db)|*.db",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
path = fileDialog.GetPath()
self.conn = sqlite3.connect(path)
self.LoadTables()
def LoadTables(self):
if self.conn:
cursor = self.conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = [row[0] for row in cursor.fetchall()]
self.listbox1.Set(tables)
def OnTableSelected(self, event):
table_name = self.listbox1.GetStringSelection()
if self.conn:
cursor = self.conn.cursor()
cursor.execute(f"PRAGMA table_info({table_name})")
columns = [row[1] for row in cursor.fetchall()]
self.listbox2.Set(columns)
def OnColumnSelected(self, event):
column_name = self.listbox2.GetStringSelection()
current_text = self.text_ctrl.GetValue()
if current_text:
current_text += f", {column_name}"
else:
current_text = column_name
self.text_ctrl.SetValue(current_text)
def OnExecuteSQL(self, event):
sql_query = self.text_ctrl.GetValue()
if self.conn and sql_query.strip():
cursor = self.conn.cursor()
try:
cursor.execute(sql_query)
results = cursor.fetchall()
self.DisplayResults(results)
except sqlite3.Error as e:
wx.MessageBox(f"An error occurred: {e}", "Error", wx.OK | wx.ICON_ERROR)
def DisplayResults(self, results):
if results:
rows = len(results)
cols = len(results[0])
self.grid.ClearGrid()
if rows > self.grid.GetNumberRows():
self.grid.AppendRows(rows - self.grid.GetNumberRows())
if cols > self.grid.GetNumberCols():
self.grid.AppendCols(cols - self.grid.GetNumberCols())
for i, row in enumerate(results):
for j, value in enumerate(row):
self.grid.SetCellValue(i, j, str(value))
if __name__ == '__main__':
app = wx.App(False)
frame = SQLiteBrowser(None)
frame.Show(True)
app.MainLoop()
代码讲解
1. 打开数据库
def OnOpen(self, event):
with wx.FileDialog(self, "Open SQLite file", wildcard="SQLite files (*.db)|*.db",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
path = fileDialog.GetPath()
self.conn = sqlite3.connect(path)
self.LoadTables()
这里,我们使用 wx.FileDialog
来打开文件选择对话框。用户选择一个SQLite数据库文件后,我们使用 sqlite3.connect()
方法建立数据库连接,并调用 LoadTables
方法列出所有表名。
2. 列出表名和字段名
def LoadTables(self):
if self.conn:
cursor = self.conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = [row[0] for row in cursor.fetchall()]
self.listbox1.Set(tables)
LoadTables
方法通过执行 SELECT name FROM sqlite_master WHERE type='table';
查询来获取所有表名,并将其添加到左侧的 ListBox
中。
def OnTableSelected(self, event):
table_name = self.listbox1.GetStringSelection()
if self.conn:
cursor = self.conn.cursor()
cursor.execute(f"PRAGMA table_info({table_name})")
columns = [row[1] for row in cursor.fetchall()]
self.listbox2.Set(columns)
当用户点击某个表名时,OnTableSelected
方法会被调用,它使用 PRAGMA table_info(table_name)
查询该表的所有字段名,并将其显示在中间的 ListBox
中。
3. 构建和执行SQL查询
def OnColumnSelected(self, event):
column_name = self.listbox2.GetStringSelection()
current_text = self.text_ctrl.GetValue()
if current_text:
current_text += f", {column_name}"
else:
current_text = column_name
self.text_ctrl.SetValue(current_text)
用户点击字段名时,OnColumnSelected
方法会将字段名追加到右侧的SQL输入框中,帮助用户快速构建SQL查询语句。
def OnExecuteSQL(self, event):
sql_query = self.text_ctrl.GetValue()
if self.conn and sql_query.strip():
cursor = self.conn.cursor()
try:
cursor.execute(sql_query)
results = cursor.fetchall()
self.DisplayResults(results)
except sqlite3.Error as e:
wx.MessageBox(f"An error occurred: {e}", "Error", wx.OK | wx.ICON_ERROR)
点击“Execute SQL”按钮后,OnExecuteSQL
方法将执行输入框中的SQL语句,并调用 DisplayResults
方法将查询结果展示在网格里。
4. 显示查询结果
def DisplayResults(self, results):
if results:
rows = len(results)
cols = len(results[0])
self.grid.ClearGrid()
if rows > self.grid.GetNumberRows():
self.grid.AppendRows(rows - self.grid.GetNumberRows())
if cols > self.grid.GetNumberCols():
self.grid.AppendCols(cols - self.grid.GetNumberCols())
for i, row in enumerate(results):
for j, value in enumerate(row):
self.grid.SetCellValue(i, j, str(value))
DisplayResults
方法会根据查询结果动态调整网格的大小,并将查询结果逐个填充到网格中。
结果如下
结语
通过上述代码,我们已经成功创建了一个简单的SQLite数据库浏览器,它可以帮助你快速查看和操作数据库中的数据。这个项目非常适合用作学习 wxPython
和 sqlite3
的入门项目,你可以在此基础上进一步扩展功能,如支持更多的SQL操作、增加数据编辑功能、或改进用户界面。