如何添加小部件以显示数据库中的 SQLite 数据?
How do I add a widget to display SQLite data from data base?
预先抱歉post的长度。我尝试了大约 10 种不同的方法来解决我的问题,但没有成功。我想提供最多的上下文。
我是 Pyqt5 的新手。我正在制作一个联系人应用程序,我可以使用 pyqt5 GUI 应用程序将数据输入到 sqlite3 'contacts.db' 文件中。我在应用程序的左侧有 GUI 输入字段。我一直卡住的地方是如何在 GUI 应用程序右侧的显示框中显示 'contacts.db' 文件的内容?
截图如下:
到目前为止,这是我的代码:
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QLabel, QLineEdit
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtCore import QSize
from sqlite3 import *
class MainWindow(QMainWindow):
# Creating Main drop window
def __init__(self):
QMainWindow.__init__(self)
# Sets dimentions for main drop window
self.setMinimumSize(QSize(1000, 425))
# Sets title for main drop window
self.setWindowTitle("Contacts")
def firstname():
# Creates a label for first field
self.nameLabel1 = QLabel(self)
# Creates label text for first label
self.nameLabel1.setText('First Name: ')
# Creates first field
self.line1 = QLineEdit(self)
# Sets placement for first field
self.line1.move(95, 50)
# Sets size for first field
self.line1.resize(200, 32)
# Sets placement for first label
self.nameLabel1.move(20, 50)
firstname()
def lastname():
self.nameLabel2 = QLabel(self)
self.nameLabel2.setText('Last Name: ')
self.line2 = QLineEdit(self)
self.line2.move(95, 100)
self.line2.resize(200, 32)
self.nameLabel2.move(20, 100)
lastname()
def email():
self.nameLabel3 = QLabel(self)
self.nameLabel3.setText('Email: ')
self.line3 = QLineEdit(self)
self.line3.move(95, 150)
self.line3.resize(200, 32)
self.nameLabel3.move(20, 150)
email()
def phone():
self.nameLabel4 = QLabel(self)
self.nameLabel4.setText('Phone: ')
self.line4 = QLineEdit(self)
self.line4.move(95, 200)
self.line4.resize(200, 32)
self.nameLabel4.move(20, 200)
phone()
def phone():
self.nameLabel5 = QLabel(self)
self.nameLabel5.setText('Location: ')
self.line5 = QLineEdit(self)
self.line5.move(95, 250)
self.line5.resize(200, 32)
self.nameLabel5.move(20, 250)
phone()
def button():
# Creates button, and button label
pybutton1 = QPushButton('Add Contact', self)
# Creates framwork for button funtion
pybutton1.clicked.connect(self.clickMethod1)
# Sets button size
pybutton1.resize(200,32)
# Sets button placement
pybutton1.move(95, 325)
button()
# Creates action that will be preformed when first button is pressed
def clickMethod1(self):
conn = connect('Contacts.db')
c = conn.cursor()
first = self.line1.text()
last = self.line2.text()
email = self.line3.text()
phone = self.line4.text()
loc = self.line5.text()
c.execute(f"""INSERT INTO contacts VALUES('{first}',
'{last}', '{email}', '{phone}', '{loc}')
""")
conn.commit()
conn.close()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit( app.exec_() )
要创建与我相同的数据库,您可以 运行 在 python:
from sqlite3 import *
conn = connect('Contacts.db')
c = conn.cursor()
# Make table
def make():
c.execute("""CREATE TABLE IF NOT EXISTS contacts(
first TEXT,
last TEXT,
email TEXT,
phone TEXT,
location TEXT
)""")
make()
conn.commit()
conn.close()
非常感谢您的帮助!
Qt 已经通过 QtSql 模块提供了对 SQL 的支持,因此您通常不需要使用单独的 sql 模块进行通用使用。
数据使用 model 加载,最终使用 view 显示(阅读更多关于 Model/View Programming 范例的信息Qt.
您基本上执行以下操作:
- 加载数据库引擎;
- select一个数据库;
- 创建模型(通常是QSqlTableModel);
- 创建视图(通常是 QTableView);
- 设置该视图的模型,使用
setModel()
;
在下面的示例中,您可以看到模型 已连接 到数据库,并且由于修改是直接对模型进行的,因此 table 是随之自动更新。
请注意,我修改了你的代码,因为它有很多问题:首先,QMainWindow 应该 always 有一个中央小部件,然后你也应该始终使用 layout managers 而不是任意大小和位置;我还删除了 __init__
中的函数,因为它们是不必要的,只会让代码分散阅读的注意力。
from PyQt5 import QtCore, QtWidgets, QtSql
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
central = QtWidgets.QWidget()
mainLayout = QtWidgets.QGridLayout(central)
mainLayout.setColumnStretch(0, 1)
mainLayout.setColumnStretch(1, 2)
formLayout = QtWidgets.QFormLayout()
mainLayout.addLayout(formLayout, 0, 0)
self.firstNameEdit = QtWidgets.QLineEdit()
self.lastNameEdit = QtWidgets.QLineEdit()
self.emailEdit = QtWidgets.QLineEdit()
self.phoneEdit = QtWidgets.QLineEdit()
self.locEdit = QtWidgets.QLineEdit()
formLayout.addRow('First name:', self.firstNameEdit)
formLayout.addRow('Last name:', self.lastNameEdit)
formLayout.addRow('Email:', self.emailEdit)
formLayout.addRow('Phone:', self.phoneEdit)
formLayout.addRow('Location:', self.locEdit)
self.addButton = QtWidgets.QPushButton('Add contact', enabled=False)
mainLayout.addWidget(self.addButton, 1, 0)
self.table = QtWidgets.QTableView()
mainLayout.addWidget(self.table, 0, 1, 2, 1)
self.table.setEditTriggers(self.table.NoEditTriggers)
self.setCentralWidget(central)
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('Contacts.db')
self.model = QtSql.QSqlTableModel()
self.model.setTable('contacts')
self.model.select()
self.table.setModel(self.model)
self.mandatoryFields = self.firstNameEdit, self.lastNameEdit
self.otherFields = self.emailEdit, self.phoneEdit, self.locEdit
self.allFields = self.mandatoryFields + self.otherFields
for field in self.allFields:
field.textChanged.connect(self.validate)
self.addButton.clicked.connect(self.addRecord)
def addRecord(self):
record = self.model.record()
for i, field in enumerate(self.allFields):
record.setValue(i, field.text())
row = self.model.rowCount()
self.model.insertRow(row)
self.model.setRecord(row, record)
def validate(self):
for field in self.mandatoryFields:
if not field.text():
self.addButton.setEnabled(False)
return
for field in self.otherFields:
if field.text():
break
else:
self.addButton.setEnabled(False)
return
self.addButton.setEnabled(True)
另请注意,Qt 提供了非常方便的 class、QDataWidgetMapper,它允许将 单个 小部件与模型的字段连接起来。通过这种方式,您可以在用户 select 索引时自动更新字段,或者使用所有字段更新数据库。
这里是上面代码的一个稍微修改的版本,实现了映射器(为了简单起见,我再次发布了整个代码,因为修改太复杂了):
from PyQt5 import QtCore, QtWidgets, QtSql
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
central = QtWidgets.QWidget()
mainLayout = QtWidgets.QGridLayout(central)
mainLayout.setColumnStretch(0, 1)
mainLayout.setColumnStretch(1, 2)
formLayout = QtWidgets.QFormLayout()
mainLayout.addLayout(formLayout, 0, 0)
self.firstNameEdit = QtWidgets.QLineEdit()
self.lastNameEdit = QtWidgets.QLineEdit()
self.emailEdit = QtWidgets.QLineEdit()
self.phoneEdit = QtWidgets.QLineEdit()
self.locEdit = QtWidgets.QLineEdit()
formLayout.addRow('First name:', self.firstNameEdit)
formLayout.addRow('Last name:', self.lastNameEdit)
formLayout.addRow('Email:', self.emailEdit)
formLayout.addRow('Phone:', self.phoneEdit)
formLayout.addRow('Location:', self.locEdit)
self.updateButton = QtWidgets.QPushButton('Update contact', enabled=False)
self.addButton = QtWidgets.QPushButton('Add contact', enabled=False)
buttonLayout = QtWidgets.QHBoxLayout()
buttonLayout.addWidget(self.updateButton)
buttonLayout.addWidget(self.addButton)
mainLayout.addLayout(buttonLayout, 1, 0)
self.table = QtWidgets.QTableView()
mainLayout.addWidget(self.table, 0, 1, 2, 1)
self.table.setEditTriggers(self.table.NoEditTriggers)
self.setCentralWidget(central)
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('Contacts.db')
self.model = QtSql.QSqlTableModel()
self.model.setTable('contacts')
self.model.select()
self.table.setModel(self.model)
self.table.setSelectionMode(self.table.SingleSelection)
self.mandatoryFields = self.firstNameEdit, self.lastNameEdit
self.otherFields = self.emailEdit, self.phoneEdit, self.locEdit
self.allFields = self.mandatoryFields + self.otherFields
self.mapper = QtWidgets.QDataWidgetMapper()
self.mapper.setModel(self.model)
self.mapper.setSubmitPolicy(self.mapper.ManualSubmit)
for i, field in enumerate(self.allFields):
field.textChanged.connect(self.validate)
self.mapper.addMapping(field, i)
self.addButton.clicked.connect(self.addRecord)
self.updateButton.clicked.connect(self.updateRecord)
self.table.selectionModel().selectionChanged.connect(self.selectionChanged)
self.mapper.currentIndexChanged.connect(self.validate)
self.table.doubleClicked.connect(self.doubleClicked)
self.table.viewport().installEventFilter(self)
def eventFilter(self, obj, event):
if event.type() == event.MouseButtonPress:
# clear all fields when clicking on an empty area of the table
index = self.table.indexAt(event.pos())
if not index.isValid():
self.table.selectionModel().select(
index, QtCore.QItemSelectionModel.ClearAndSelect)
return super().eventFilter(obj, event)
def doubleClicked(self, index):
widget = self.mapper.mappedWidgetAt(index.column())
if widget:
widget.setFocus()
def selectedRow(self):
selected = self.table.selectedIndexes()
if selected:
return selected[-1].row()
return -1
def selectionChanged(self):
row = self.selectedRow()
self.mapper.setCurrentIndex(row)
if row < 0:
for field in self.allFields:
field.setText('')
self.validate()
def addRecord(self):
# we cannot use submit(), as it will use the *current* index, nor we can
# insert the new row and set the new index, as it would clear all fields
record = self.model.record()
for i, field in enumerate(self.allFields):
record.setValue(i, field.text())
row = self.model.rowCount()
self.model.insertRow(row)
self.model.setRecord(row, record)
self.table.selectionModel().select(self.model.index(row, 0),
QtCore.QItemSelectionModel.ClearAndSelect)
def updateRecord(self):
row = self.selectedRow()
if row < 0:
self.updateButton.setEnabled(False)
return
self.mapper.submit()
def validate(self):
valid = True
for field in self.mandatoryFields:
if not field.text():
valid = False
break
else:
for field in self.otherFields:
if field.text():
break
else:
valid = False
self.addButton.setEnabled(valid)
self.updateButton.setEnabled(valid and bool(self.table.selectedIndexes()))
预先抱歉post的长度。我尝试了大约 10 种不同的方法来解决我的问题,但没有成功。我想提供最多的上下文。
我是 Pyqt5 的新手。我正在制作一个联系人应用程序,我可以使用 pyqt5 GUI 应用程序将数据输入到 sqlite3 'contacts.db' 文件中。我在应用程序的左侧有 GUI 输入字段。我一直卡住的地方是如何在 GUI 应用程序右侧的显示框中显示 'contacts.db' 文件的内容?
截图如下:
到目前为止,这是我的代码:
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QLabel, QLineEdit
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtCore import QSize
from sqlite3 import *
class MainWindow(QMainWindow):
# Creating Main drop window
def __init__(self):
QMainWindow.__init__(self)
# Sets dimentions for main drop window
self.setMinimumSize(QSize(1000, 425))
# Sets title for main drop window
self.setWindowTitle("Contacts")
def firstname():
# Creates a label for first field
self.nameLabel1 = QLabel(self)
# Creates label text for first label
self.nameLabel1.setText('First Name: ')
# Creates first field
self.line1 = QLineEdit(self)
# Sets placement for first field
self.line1.move(95, 50)
# Sets size for first field
self.line1.resize(200, 32)
# Sets placement for first label
self.nameLabel1.move(20, 50)
firstname()
def lastname():
self.nameLabel2 = QLabel(self)
self.nameLabel2.setText('Last Name: ')
self.line2 = QLineEdit(self)
self.line2.move(95, 100)
self.line2.resize(200, 32)
self.nameLabel2.move(20, 100)
lastname()
def email():
self.nameLabel3 = QLabel(self)
self.nameLabel3.setText('Email: ')
self.line3 = QLineEdit(self)
self.line3.move(95, 150)
self.line3.resize(200, 32)
self.nameLabel3.move(20, 150)
email()
def phone():
self.nameLabel4 = QLabel(self)
self.nameLabel4.setText('Phone: ')
self.line4 = QLineEdit(self)
self.line4.move(95, 200)
self.line4.resize(200, 32)
self.nameLabel4.move(20, 200)
phone()
def phone():
self.nameLabel5 = QLabel(self)
self.nameLabel5.setText('Location: ')
self.line5 = QLineEdit(self)
self.line5.move(95, 250)
self.line5.resize(200, 32)
self.nameLabel5.move(20, 250)
phone()
def button():
# Creates button, and button label
pybutton1 = QPushButton('Add Contact', self)
# Creates framwork for button funtion
pybutton1.clicked.connect(self.clickMethod1)
# Sets button size
pybutton1.resize(200,32)
# Sets button placement
pybutton1.move(95, 325)
button()
# Creates action that will be preformed when first button is pressed
def clickMethod1(self):
conn = connect('Contacts.db')
c = conn.cursor()
first = self.line1.text()
last = self.line2.text()
email = self.line3.text()
phone = self.line4.text()
loc = self.line5.text()
c.execute(f"""INSERT INTO contacts VALUES('{first}',
'{last}', '{email}', '{phone}', '{loc}')
""")
conn.commit()
conn.close()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit( app.exec_() )
要创建与我相同的数据库,您可以 运行 在 python:
from sqlite3 import *
conn = connect('Contacts.db')
c = conn.cursor()
# Make table
def make():
c.execute("""CREATE TABLE IF NOT EXISTS contacts(
first TEXT,
last TEXT,
email TEXT,
phone TEXT,
location TEXT
)""")
make()
conn.commit()
conn.close()
非常感谢您的帮助!
Qt 已经通过 QtSql 模块提供了对 SQL 的支持,因此您通常不需要使用单独的 sql 模块进行通用使用。
数据使用 model 加载,最终使用 view 显示(阅读更多关于 Model/View Programming 范例的信息Qt.
您基本上执行以下操作:
- 加载数据库引擎;
- select一个数据库;
- 创建模型(通常是QSqlTableModel);
- 创建视图(通常是 QTableView);
- 设置该视图的模型,使用
setModel()
;
在下面的示例中,您可以看到模型 已连接 到数据库,并且由于修改是直接对模型进行的,因此 table 是随之自动更新。
请注意,我修改了你的代码,因为它有很多问题:首先,QMainWindow 应该 always 有一个中央小部件,然后你也应该始终使用 layout managers 而不是任意大小和位置;我还删除了 __init__
中的函数,因为它们是不必要的,只会让代码分散阅读的注意力。
from PyQt5 import QtCore, QtWidgets, QtSql
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
central = QtWidgets.QWidget()
mainLayout = QtWidgets.QGridLayout(central)
mainLayout.setColumnStretch(0, 1)
mainLayout.setColumnStretch(1, 2)
formLayout = QtWidgets.QFormLayout()
mainLayout.addLayout(formLayout, 0, 0)
self.firstNameEdit = QtWidgets.QLineEdit()
self.lastNameEdit = QtWidgets.QLineEdit()
self.emailEdit = QtWidgets.QLineEdit()
self.phoneEdit = QtWidgets.QLineEdit()
self.locEdit = QtWidgets.QLineEdit()
formLayout.addRow('First name:', self.firstNameEdit)
formLayout.addRow('Last name:', self.lastNameEdit)
formLayout.addRow('Email:', self.emailEdit)
formLayout.addRow('Phone:', self.phoneEdit)
formLayout.addRow('Location:', self.locEdit)
self.addButton = QtWidgets.QPushButton('Add contact', enabled=False)
mainLayout.addWidget(self.addButton, 1, 0)
self.table = QtWidgets.QTableView()
mainLayout.addWidget(self.table, 0, 1, 2, 1)
self.table.setEditTriggers(self.table.NoEditTriggers)
self.setCentralWidget(central)
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('Contacts.db')
self.model = QtSql.QSqlTableModel()
self.model.setTable('contacts')
self.model.select()
self.table.setModel(self.model)
self.mandatoryFields = self.firstNameEdit, self.lastNameEdit
self.otherFields = self.emailEdit, self.phoneEdit, self.locEdit
self.allFields = self.mandatoryFields + self.otherFields
for field in self.allFields:
field.textChanged.connect(self.validate)
self.addButton.clicked.connect(self.addRecord)
def addRecord(self):
record = self.model.record()
for i, field in enumerate(self.allFields):
record.setValue(i, field.text())
row = self.model.rowCount()
self.model.insertRow(row)
self.model.setRecord(row, record)
def validate(self):
for field in self.mandatoryFields:
if not field.text():
self.addButton.setEnabled(False)
return
for field in self.otherFields:
if field.text():
break
else:
self.addButton.setEnabled(False)
return
self.addButton.setEnabled(True)
另请注意,Qt 提供了非常方便的 class、QDataWidgetMapper,它允许将 单个 小部件与模型的字段连接起来。通过这种方式,您可以在用户 select 索引时自动更新字段,或者使用所有字段更新数据库。
这里是上面代码的一个稍微修改的版本,实现了映射器(为了简单起见,我再次发布了整个代码,因为修改太复杂了):
from PyQt5 import QtCore, QtWidgets, QtSql
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
central = QtWidgets.QWidget()
mainLayout = QtWidgets.QGridLayout(central)
mainLayout.setColumnStretch(0, 1)
mainLayout.setColumnStretch(1, 2)
formLayout = QtWidgets.QFormLayout()
mainLayout.addLayout(formLayout, 0, 0)
self.firstNameEdit = QtWidgets.QLineEdit()
self.lastNameEdit = QtWidgets.QLineEdit()
self.emailEdit = QtWidgets.QLineEdit()
self.phoneEdit = QtWidgets.QLineEdit()
self.locEdit = QtWidgets.QLineEdit()
formLayout.addRow('First name:', self.firstNameEdit)
formLayout.addRow('Last name:', self.lastNameEdit)
formLayout.addRow('Email:', self.emailEdit)
formLayout.addRow('Phone:', self.phoneEdit)
formLayout.addRow('Location:', self.locEdit)
self.updateButton = QtWidgets.QPushButton('Update contact', enabled=False)
self.addButton = QtWidgets.QPushButton('Add contact', enabled=False)
buttonLayout = QtWidgets.QHBoxLayout()
buttonLayout.addWidget(self.updateButton)
buttonLayout.addWidget(self.addButton)
mainLayout.addLayout(buttonLayout, 1, 0)
self.table = QtWidgets.QTableView()
mainLayout.addWidget(self.table, 0, 1, 2, 1)
self.table.setEditTriggers(self.table.NoEditTriggers)
self.setCentralWidget(central)
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('Contacts.db')
self.model = QtSql.QSqlTableModel()
self.model.setTable('contacts')
self.model.select()
self.table.setModel(self.model)
self.table.setSelectionMode(self.table.SingleSelection)
self.mandatoryFields = self.firstNameEdit, self.lastNameEdit
self.otherFields = self.emailEdit, self.phoneEdit, self.locEdit
self.allFields = self.mandatoryFields + self.otherFields
self.mapper = QtWidgets.QDataWidgetMapper()
self.mapper.setModel(self.model)
self.mapper.setSubmitPolicy(self.mapper.ManualSubmit)
for i, field in enumerate(self.allFields):
field.textChanged.connect(self.validate)
self.mapper.addMapping(field, i)
self.addButton.clicked.connect(self.addRecord)
self.updateButton.clicked.connect(self.updateRecord)
self.table.selectionModel().selectionChanged.connect(self.selectionChanged)
self.mapper.currentIndexChanged.connect(self.validate)
self.table.doubleClicked.connect(self.doubleClicked)
self.table.viewport().installEventFilter(self)
def eventFilter(self, obj, event):
if event.type() == event.MouseButtonPress:
# clear all fields when clicking on an empty area of the table
index = self.table.indexAt(event.pos())
if not index.isValid():
self.table.selectionModel().select(
index, QtCore.QItemSelectionModel.ClearAndSelect)
return super().eventFilter(obj, event)
def doubleClicked(self, index):
widget = self.mapper.mappedWidgetAt(index.column())
if widget:
widget.setFocus()
def selectedRow(self):
selected = self.table.selectedIndexes()
if selected:
return selected[-1].row()
return -1
def selectionChanged(self):
row = self.selectedRow()
self.mapper.setCurrentIndex(row)
if row < 0:
for field in self.allFields:
field.setText('')
self.validate()
def addRecord(self):
# we cannot use submit(), as it will use the *current* index, nor we can
# insert the new row and set the new index, as it would clear all fields
record = self.model.record()
for i, field in enumerate(self.allFields):
record.setValue(i, field.text())
row = self.model.rowCount()
self.model.insertRow(row)
self.model.setRecord(row, record)
self.table.selectionModel().select(self.model.index(row, 0),
QtCore.QItemSelectionModel.ClearAndSelect)
def updateRecord(self):
row = self.selectedRow()
if row < 0:
self.updateButton.setEnabled(False)
return
self.mapper.submit()
def validate(self):
valid = True
for field in self.mandatoryFields:
if not field.text():
valid = False
break
else:
for field in self.otherFields:
if field.text():
break
else:
valid = False
self.addButton.setEnabled(valid)
self.updateButton.setEnabled(valid and bool(self.table.selectedIndexes()))