我决定使用和学习Qt本机QtSql类。使用QSqlQuery()很简单,很像SqlAlchemy。
我尝试使用QTableView / Model方法,但是成功非常有限。
我的参考文档是“使用Python和Qt进行快速GUI编程”,但仍然可用。
经过大量的实验,我部分成功了,但是我当前的问题有点困惑,并且我当前的Web搜索没有帮助(到目前为止)
该表单显示前两个记录所请求的信息,但不显示随后的记录(后两个)的信息。数据库中有四个记录。
数据库故障
主表“ tblRecipe”包含键,配方名称,类别和说明支持表“ tblIngrediants”包含一种到多种配方成分:字段为:“ ingrediantKey”,“ ingrediantDescription”,“ ingrediantRecipeKey”,“ ingrediantQuantity”查找表的最终表将“ tblRecipe”中的类别整数更改为人类可读的文本。我尚未尝试合并此表。
问题:为什么我要获得前2条记录的正确信息而不是后2条的正确信息。
我已经包含了与我的问题有关的部分代码。声明我的小部件的代码
class RecipeDlg(QDialog):
FIRST, PREV, NEXT, LAST = range(4)
def __init__(self, parent=None):
super(RecipeDlg, self).__init__(parent)
catLabel = QLabel("Category:")
self.catEdit = QLineEdit()
catLabel.setBuddy(self.catEdit)
nameLabel = QLabel("Name:")
self.nameEdit = QLineEdit()
nameLabel.setBuddy(self.nameEdit)
IngrediantLabel = QLabel("Ingrediants:")
self.tvIngrediants = QTableView()
descriptionLabel = QLabel("Description:")
self.descriptionEdit = QTextEdit()
descriptionLabel.setBuddy(self.descriptionEdit)
firstButton = QPushButton()
firstButton.setIcon(QIcon(":/first.png"))
prevButton = QPushButton()
prevButton.setIcon(QIcon(":/prev.png"))
nextButton = QPushButton()
nextButton.setIcon(QIcon(":/next.png"))
lastButton = QPushButton()
lastButton.setIcon(QIcon(":/last.png"))
addButton = QPushButton("&Add")
addButton.setIcon(QIcon(":/add.png"))
deleteButton = QPushButton("&Delete")
deleteButton.setIcon(QIcon(":/delete.png"))
quitButton = QPushButton("&Quit")
quitButton.setIcon(QIcon(":/quit.png"))
addButton.setFocusPolicy(Qt.NoFocus)
deleteButton.setFocusPolicy(Qt.NoFocus)
声明模型和视图的代码
self.model = QSqlTableModel(self)
self.model.setTable("tblRecipe")
self.model.setSort(RECIPECATEGORY, Qt.AscendingOrder)
self.model.select()
self.ingredModel = QSqlRelationalTableModel(self)
self.ingredModel.setTable("tblIngrediants")
self.ingredModel.setRelation(INGREDIANTKEY,
QSqlRelation("tblRecipe", "recipeKey", "recipeName"))
self.ingredModel.setHeaderData(INGREDIANTKEY, Qt.Horizontal, "id")
self.ingredModel.setHeaderData(INGREDIANTDESCRIPTION, Qt.Horizontal,
"Description")
self.ingredModel.setHeaderData(INGREDIANTQUANTITY, Qt.Horizontal, "Quantity")
self.ingredModel.select()
self.tvIngrediants.setModel(self.ingredModel) # connect to the model
self.tvIngrediants.setSelectionMode(QTableView.SingleSelection)
self.tvIngrediants.setSelectionBehavior(QTableView.SelectRows)
self.tvIngrediants.setColumnHidden(INGREDIANTKEY, True)
self.tvIngrediants.setColumnHidden(2, True)
self.tvIngrediants.resizeColumnsToContents()
self.mapper = QDataWidgetMapper(self)
self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
self.mapper.setModel(self.model)
self.mapper.setItemDelegate(QSqlRelationalDelegate(self))
self.mapper.addMapping(self.catEdit, RECIPECATEGORY)
self.mapper.addMapping(self.nameEdit, RECIPENAME)
self.mapper.addMapping(self.descriptionEdit, RECIPEDESCRIPTION)
#relationModel = self.ingredModel.relationModel(INGREDIANTRECIPEKEY)
#self.tvIngrediants.setModel(relationModel)
self.mapper.addMapping(self.tvIngrediants, INGREDIANTRECIPEKEY)
self.mapper.toFirst()
self.displayIngred()
该函数的代码:self.displayIngred()
def displayIngred(self):
index = self.mapper.currentIndex()
record = self.model.record(index)
id = record.value("recipeKey")
self.ingredModel.setFilter("ingrediantRecipeKey = {}".format(id))
self.ingredModel.select()
self.tvIngrediants.horizontalHeader().setVisible(
self.ingredModel.rowCount() > 0)
打开数据库并显示表单的代码
def main():
app = QApplication(sys.argv)
filename = os.path.join(os.path.dirname(__file__), "Recipes.db")
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(filename)
if not db.open():
QMessageBox.warning(None, "Phone Log",
"Database Error: {}".format(db.lastError().text()))
sys.exit(1)
form = RecipeDlg()
form.show()
sys.exit(app.exec_())
结果图像:
记录1
记录4,但没有出现成分
最小的可复制示例:应用程序有204行,将消除布局定义,并且不重要的函数将仅具有Pass占位符。
import os
RECIPEKEY, RECIPENAME, RECIPECATEGORY, RECIPEDESCRIPTION = range(4)
INGREDIANTKEY, INGREDIANTDESCRIPTION, INGREDIANTRECIPEKEY, INGREDIANTQUANTITY = range(4)
class RecipeDlg(QDialog):
FIRST, PREV, NEXT, LAST = range(4)
def __init__(self, parent=None):
super(RecipeDlg, self).__init__(parent)
catLabel = QLabel("Category:")
self.catEdit = QLineEdit()
catLabel.setBuddy(self.catEdit)
nameLabel = QLabel("Name:")
self.nameEdit = QLineEdit()
nameLabel.setBuddy(self.nameEdit)
IngrediantLabel = QLabel("Ingrediants:")
self.tvIngrediants = QTableView()
descriptionLabel = QLabel("Description:")
self.descriptionEdit = QTextEdit()
descriptionLabel.setBuddy(self.descriptionEdit)
firstButton = QPushButton()
firstButton.setIcon(QIcon(":/first.png"))
prevButton = QPushButton()
prevButton.setIcon(QIcon(":/prev.png"))
nextButton = QPushButton()
nextButton.setIcon(QIcon(":/next.png"))
lastButton = QPushButton()
lastButton.setIcon(QIcon(":/last.png"))
addButton = QPushButton("&Add")
addButton.setIcon(QIcon(":/add.png"))
deleteButton = QPushButton("&Delete")
deleteButton.setIcon(QIcon(":/delete.png"))
quitButton = QPushButton("&Quit")
quitButton.setIcon(QIcon(":/quit.png"))
addButton.setFocusPolicy(Qt.NoFocus)
deleteButton.setFocusPolicy(Qt.NoFocus)
fieldLayout = QGridLayout()
... eliminated
self.setLayout(layout)
self.model = QSqlTableModel(self)
self.model.setTable("tblRecipe")
self.model.setSort(RECIPECATEGORY, Qt.AscendingOrder)
self.model.select()
self.ingredModel = QSqlRelationalTableModel(self)
self.ingredModel.setTable("tblIngrediants")
self.ingredModel.setRelation(INGREDIANTKEY,
QSqlRelation("tblRecipe", "recipeKey", "recipeName"))
self.ingredModel.setHeaderData(INGREDIANTKEY, Qt.Horizontal, "id")
self.ingredModel.setHeaderData(INGREDIANTDESCRIPTION, Qt.Horizontal,
"Description")
self.ingredModel.setHeaderData(INGREDIANTQUANTITY, Qt.Horizontal, "Quantity")
self.ingredModel.select()
self.tvIngrediants.setModel(self.ingredModel) # connect to the model
self.tvIngrediants.setSelectionMode(QTableView.SingleSelection)
self.tvIngrediants.setSelectionBehavior(QTableView.SelectRows)
self.tvIngrediants.setColumnHidden(INGREDIANTKEY, True)
self.tvIngrediants.setColumnHidden(2, True)
self.tvIngrediants.resizeColumnsToContents()
self.mapper = QDataWidgetMapper(self)
self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
self.mapper.setModel(self.model)
self.mapper.setItemDelegate(QSqlRelationalDelegate(self))
self.mapper.addMapping(self.catEdit, RECIPECATEGORY)
self.mapper.addMapping(self.nameEdit, RECIPENAME)
self.mapper.addMapping(self.descriptionEdit, RECIPEDESCRIPTION)
#relationModel = self.ingredModel.relationModel(INGREDIANTRECIPEKEY)
#self.tvIngrediants.setModel(relationModel)
self.mapper.addMapping(self.tvIngrediants, INGREDIANTRECIPEKEY)
self.mapper.toFirst()
self.displayIngred()
firstButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.FIRST))
prevButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.PREV))
nextButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.NEXT))
lastButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.LAST))
addButton.clicked.connect(self.addRecord)
deleteButton.clicked.connect(self.deleteRecord)
quitButton.clicked.connect(self.accept)
self.setWindowTitle("Recipes")
def displayIngred(self):
index = self.mapper.currentIndex()
record = self.model.record(index)
id = record.value("recipeKey")
self.ingredModel.setFilter("ingrediantRecipeKey = {}".format(id))
self.ingredModel.select()
self.tvIngrediants.horizontalHeader().setVisible(
self.ingredModel.rowCount() > 0)
def reject(self):
self.accept()
def accept(self):
self.mapper.submit()
QDialog.accept(self)
def addRecord(self):
pass
def deleteRecord(self):
pass
def saveRecord(self, where):
row = self.mapper.currentIndex()
self.mapper.submit()
if where == RecipeDlg.FIRST:
row = 0
elif where == RecipeDlg.PREV:
row = 0 if row <= 1 else row - 1
elif where == RecipeDlg.NEXT:
row += 1
if row >= self.model.rowCount():
row = self.model.rowCount() - 1
elif where == RecipeDlg.LAST:
row = self.model.rowCount() - 1
self.mapper.setCurrentIndex(row)
self.displayIngred()
def main():
app = QApplication(sys.argv)
filename = os.path.join(os.path.dirname(__file__), "Recipes.db")
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(filename)
if not db.open():
QMessageBox.warning(None, "Recipes",
"Database Error: {}".format(db.lastError().text()))
sys.exit(1)
form = RecipeDlg()
form.show()
sys.exit(app.exec_())
main()
最小的可复制示例:应用程序有204行,将消除布局定义,并且不重要的函数将仅具有Pass占位符。
import os
RECIPEKEY, RECIPENAME, RECIPECATEGORY, RECIPEDESCRIPTION = range(4)
INGREDIANTKEY, INGREDIANTDESCRIPTION, INGREDIANTRECIPEKEY, INGREDIANTQUANTITY = range(4)
class RecipeDlg(QDialog):
FIRST, PREV, NEXT, LAST = range(4)
def __init__(self, parent=None):
super(RecipeDlg, self).__init__(parent)
catLabel = QLabel("Category:")
self.catEdit = QLineEdit()
catLabel.setBuddy(self.catEdit)
nameLabel = QLabel("Name:")
self.nameEdit = QLineEdit()
nameLabel.setBuddy(self.nameEdit)
IngrediantLabel = QLabel("Ingrediants:")
self.tvIngrediants = QTableView()
descriptionLabel = QLabel("Description:")
self.descriptionEdit = QTextEdit()
descriptionLabel.setBuddy(self.descriptionEdit)
firstButton = QPushButton()
firstButton.setIcon(QIcon(":/first.png"))
prevButton = QPushButton()
prevButton.setIcon(QIcon(":/prev.png"))
nextButton = QPushButton()
nextButton.setIcon(QIcon(":/next.png"))
lastButton = QPushButton()
lastButton.setIcon(QIcon(":/last.png"))
addButton = QPushButton("&Add")
addButton.setIcon(QIcon(":/add.png"))
deleteButton = QPushButton("&Delete")
deleteButton.setIcon(QIcon(":/delete.png"))
quitButton = QPushButton("&Quit")
quitButton.setIcon(QIcon(":/quit.png"))
addButton.setFocusPolicy(Qt.NoFocus)
deleteButton.setFocusPolicy(Qt.NoFocus)
fieldLayout = QGridLayout()
... eliminated
self.setLayout(layout)
self.model = QSqlTableModel(self)
self.model.setTable("tblRecipe")
self.model.setSort(RECIPECATEGORY, Qt.AscendingOrder)
self.model.select()
self.ingredModel = QSqlRelationalTableModel(self)
self.ingredModel.setTable("tblIngrediants")
self.ingredModel.setRelation(INGREDIANTKEY,
QSqlRelation("tblRecipe", "recipeKey", "recipeName"))
self.ingredModel.setHeaderData(INGREDIANTKEY, Qt.Horizontal, "id")
self.ingredModel.setHeaderData(INGREDIANTDESCRIPTION, Qt.Horizontal,
"Description")
self.ingredModel.setHeaderData(INGREDIANTQUANTITY, Qt.Horizontal, "Quantity")
self.ingredModel.select()
self.tvIngrediants.setModel(self.ingredModel) # connect to the model
self.tvIngrediants.setSelectionMode(QTableView.SingleSelection)
self.tvIngrediants.setSelectionBehavior(QTableView.SelectRows)
self.tvIngrediants.setColumnHidden(INGREDIANTKEY, True)
self.tvIngrediants.setColumnHidden(2, True)
self.tvIngrediants.resizeColumnsToContents()
self.mapper = QDataWidgetMapper(self)
self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
self.mapper.setModel(self.model)
self.mapper.setItemDelegate(QSqlRelationalDelegate(self))
self.mapper.addMapping(self.catEdit, RECIPECATEGORY)
self.mapper.addMapping(self.nameEdit, RECIPENAME)
self.mapper.addMapping(self.descriptionEdit, RECIPEDESCRIPTION)
#relationModel = self.ingredModel.relationModel(INGREDIANTRECIPEKEY)
#self.tvIngrediants.setModel(relationModel)
self.mapper.addMapping(self.tvIngrediants, INGREDIANTRECIPEKEY)
self.mapper.toFirst()
self.displayIngred()
firstButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.FIRST))
prevButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.PREV))
nextButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.NEXT))
lastButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.LAST))
addButton.clicked.connect(self.addRecord)
deleteButton.clicked.connect(self.deleteRecord)
quitButton.clicked.connect(self.accept)
self.setWindowTitle("Recipes")
def displayIngred(self):
index = self.mapper.currentIndex()
record = self.model.record(index)
id = record.value("recipeKey")
self.ingredModel.setFilter("ingrediantRecipeKey = {}".format(id))
self.ingredModel.select()
self.tvIngrediants.horizontalHeader().setVisible(
self.ingredModel.rowCount() > 0)
def reject(self):
self.accept()
def accept(self):
self.mapper.submit()
QDialog.accept(self)
def addRecord(self):
pass
def deleteRecord(self):
pass
def saveRecord(self, where):
row = self.mapper.currentIndex()
self.mapper.submit()
if where == RecipeDlg.FIRST:
row = 0
elif where == RecipeDlg.PREV:
row = 0 if row <= 1 else row - 1
elif where == RecipeDlg.NEXT:
row += 1
if row >= self.model.rowCount():
row = self.model.rowCount() - 1
elif where == RecipeDlg.LAST:
row = self.model.rowCount() - 1
self.mapper.setCurrentIndex(row)
self.displayIngred()
def main():
app = QApplication(sys.argv)
filename = os.path.join(os.path.dirname(__file__), "Recipes.db")
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(filename)
if not db.open():
QMessageBox.warning(None, "Recipes",
"Database Error: {}".format(db.lastError().text()))
sys.exit(1)
form = RecipeDlg()
form.show()
sys.exit(app.exec_())
main()