I am writing a program using python 3.4 to allow a user to enter their Name and Surname and once they hit save the data should save in the db an display on screen. The Data saves to the db fine( I know this because every time I close the program and run it the previous entry displays). My problem here is that when I enter the data and hit save, it does not automatically display on the screen in the tabelView widget. I used QT designer 4 to create the widget and my database table only contains two columns, Full_Name and Surname. How can I get my entry to display immediately after hitting the save button?
Here's my code:
import sys
from Nametest import *
from PyQt4 import QtSql, QtGui
import mysql.connector
conn=mysql.connector.connect(host="localhost", user="root", passwd="shotokan", db="name")
cursor=conn.cursor()
def createConnection():
db = QtSql.QSqlDatabase.addDatabase('QMYSQL')
db.setHostName('localhost')
db.setDatabaseName('name')
db.setUserName('root')
db.setPassword('shotokan')
db.open()
print (db.lastError().text())
return True
class MyForm(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.model = QtSql.QSqlTableModel(self)
self.model.setTable("fullname")
self.model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
self.model.select()
self.ui.tableView.setModel(self.model)
QtCore.QObject.connect(self.ui.pushButton, QtCore.SIGNAL('clicked()' ),self.InsertRecords)
def InsertRecords(self):
cursor.execute( """INSERT INTO fullname (First_Name, Surname)VALUES('%s','%s')""" %(self.ui.lineEdit.text(),self.ui.lineEdit_2.text()))
conn.commit()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
if not createConnection():
sys.exit(1)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
Here is an image of my Widget:
Don't use 2 technologies to do the same task, if you have used QSqlTableModel to display the information then use that model to do the insert:
class MyForm(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.model = QtSql.QSqlTableModel(self)
self.model.setTable("fullname")
self.model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
self.model.select()
self.ui.tableView.setModel(self.model)
self.ui.pushButton.clicked.connect(self.InsertRecords)
def InsertRecords(self):
db = self.model.database()
db.transaction()
record = self.model.record()
record.setValue("First_Name", self.ui.lineEdit.text())
record.setValue("Surname", self.ui.lineEdit_2.text())
if self.model.insertRecord(-1, record):
print("successful insertion")
self.model.submitAll()
else:
db.rollback()
Note: Do not use concatenation to create a query since your application is susceptible to SQL Injection.
Related
I have a usb barcode scanner which I am connecting to my computer. Everytime it scans a barcode, it types the data into the computer like a keyboard. My goal was to have the data be typed into PyQT5 Table widget.
I have created the table below and I simply scan the items into it. The problem is that when I scan an item, it edits the first cell, but the cursor does not move automatically to the next row so I can scan a new item into the table. I have to click on the second cell and then scan the item. Then click on the third cell and scan the item and so on.
I was wondering how I can automate it so that after an item is scanned into the first cell, it automatically moves to the next cell and waits for input from the scanner?
import sys
from PyQt5.QtWidgets import *
#Main Window
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Specimen Dashboard'
self.setWindowTitle(self.title)
self.tableWidget = QTableWidget()
self.createTable()
self.tableWidget.itemChanged.connect(self.go_to_next_row)
self.layout = QVBoxLayout()
self.layout.addWidget(self.tableWidget)
self.setLayout(self.layout)
self.show()
def go_to_next_row(self):
#Not working
#Trying to see if I can automatically move to next cell, but editing it
self.tableWidget.setItem(1,0, QTableWidgetItem("Name"))
#Create table
def createTable(self):
self.tableWidget.setRowCount(4)
self.tableWidget.setColumnCount(2)
self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.tableWidget.horizontalHeader().setSectionResizeMode(
QHeaderView.Stretch)
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
By default the scanners send an endline("\n") that is translated a Return or Enter key and this by default closes the editor, in this case that event must be intercepted, move the cursor and open the editor:
import sys
from PyQt5 import QtCore, QtWidgets
class TableWidget(QtWidgets.QTableWidget):
def keyPressEvent(self, event):
if (
event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return)
and self.state() == QtWidgets.QAbstractItemView.EditingState
):
index = self.moveCursor(
QtWidgets.QAbstractItemView.MoveNext, QtCore.Qt.NoModifier
)
self.selectionModel().setCurrentIndex(
index, QtCore.QItemSelectionModel.ClearAndSelect
)
self.edit(index)
else:
super().keyPressEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.tableWidget = TableWidget(4, 2)
self.setCentralWidget(self.tableWidget)
self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.tableWidget.horizontalHeader().setSectionResizeMode(
QtWidgets.QHeaderView.Stretch
)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
You can subclass the table and overwrite closeEditor(): the hint argument tells the view what should happen when the editor has been closed; by default, when pressing Enter the current cell data is submitted, but you can override this behavior like this:
from PyQt5 import QtGui, QtWidgets
class Table(QtWidgets.QTableView):
# leave to False for the default behavior (the next cell is the one at the
# right of the current, or the first of the next row; when set to True it
# will always go to the next row, while keeping the same column
useNextRow = False
def closeEditor(self, editor, hint):
if hint == QtWidgets.QAbstractItemDelegate.SubmitModelCache:
if self.useNextRow:
super().closeEditor(editor, hint)
current = self.currentIndex()
newIndex = current.sibling(current.row() + 1, current.column())
if newIndex.isValid():
self.setCurrentIndex(newIndex)
self.edit(newIndex)
return
else:
hint = QtWidgets.QAbstractItemDelegate.EditNextItem
super().closeEditor(editor, hint)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = Table()
test.show()
model = QtGui.QStandardItemModel(10, 5)
test.setModel(model)
sys.exit(app.exec_())
I will briefly describe my program first
Program Description
Below are the 2 widows used in the program:
Main Window (Group List)
Input Window (Student Table)
The Main Window allows users to create/edit/delete entries in Groups list (QListWidget), which shows title of each entry read from a Sqlite database(DB). The 'New' button opens a new Input Window, which allows users to insert entries in Student table (QTableWidget). '+' button adds new row to table, and '-' button removes selected row. 'Name' and 'Age' of each entry can be edited directly by clicking on a cell in the table. The 'Save' button saves the title and the table inputs(entries of students: 'Name' and 'Age') to DB and updates the 'Groups' list in the Main Window. The 'Cancel' button closes the Input Window without saving the changes made in the window.
Database
Group list (QListView)
Student table (QTableWidget)
I am using SQLite using PyQt5's Qtsql class for database. 'group_id' in Student table is FK to Group list's 'id'.
My Problem
I would like to be able to select an entry in 'Groups' list, press 'Edit' button, and show Input Window's Student table filled with data from DB, just as shown above. I tried using QDataWidgetMapper, as it worked well with populating QTextEdit and QLineEdit, but I am having trouble populating QTableWidget with it.
How to populate QTableWidget from database in this context. Is there a method I am missing in QDataWidgetMapper?
Codes
Relevant snippets of my code where I attempt to map Student table in DB to PyQt5 (Most of this is my adapted version of eyllanesc's answer to Accessing SQL data from a list entry)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self._groups_model = QtSql.QSqlTableModel(self)
self.groups_model.setTable("Groups")
self.groups_model.select()
self._student_model = QtSql.QSqlTableModel(self)
self.student_model.setTable("Student")
self.student_model.select()
self.sql_list_view = QtWidgets.QListView()
self.sql_list_view.setModel(self.groups_model)
self.sql_list_view.setModelColumn(self.groups_model.record().indexOf("group_name"))
...
#property
def macro_model(self):
return self._macro_model
#property
def sheets_model(self):
return self._sheets_model
#QtCore.pyqtSlot()
def edit(self):
ixs = self.listView_macros.selectionModel().selectedIndexes()
if ixs:
print(ixs)
d = EditDialog(self.groups_model, ixs[0].row(), self.student_model)
d.exec_()
class EditDialog(QtWidgets.QDialog):
def __init__(self, gr_model, gr_idx, std_model, parent=None):
super().__init__(parent)
self.title_le = QtWidgets.QLineEdit()
self.student_table = QtWidgets.QTableWidget(self)
groups_mapper = QtWidgets.QDataWidgetMapper(
self, submitPolicy=QtWidgets.QDataWidgetMapper.ManualSubmit
)
groups_mapper.setModel(gr_model)
groups_mapper.addMapping(self.title_le, gr_model.record().indexOf("group_name"))
groups_mapper.setCurrentIndex(gr_idx)
student_mapper = QtWidgets.QDataWidgetMapper(
self, submitPolicy=QtWidgets.QDataWidgetMapper.ManualSubmit
)
student_mapper.setModel(std_model)
student_mapper.addMapping(self.student_table, ????) # << I am having trouble here
You are confusing the concepts(I recommend you review the official Qt documentation and test the PyQt5 examples that are in its source code). QDataWidgetMapper is used to map a single row of a model so it will not be useful to handle several rows. You should not use QTableWidget but a QTableView with a QSqlTableModel with a filter based on the FK. Then applying the same logic that was implemented to add groups to add students.
from PyQt5 import QtCore, QtGui, QtWidgets, QtSql
def create_connection(database):
db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(database)
if not db.open():
print("Cannot open database")
print(
"Unable to establish a database connection.\n"
"This example needs SQLite support. Please read "
"the Qt SQL driver documentation for information "
"how to build it.\n\n"
"Click Cancel to exit."
)
return False
query = QtSql.QSqlQuery()
if not query.exec_(
"""CREATE TABLE IF NOT EXISTS Groups (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"group_name" TEXT)"""
):
print(query.lastError().text())
return False
if not query.exec_(
"""CREATE TABLE IF NOT EXISTS Student (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"group_id" INTEGER,
"name" TEXT,
"age" INTEGER,
FOREIGN KEY(group_id) REFERENCES Groups(id))"""
):
print(query.lastError().text())
return False
return True
class AddGroupDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.title_le = QtWidgets.QLineEdit()
button_box = QtWidgets.QDialogButtonBox(self)
button_box.setOrientation(QtCore.Qt.Horizontal)
button_box.setStandardButtons(
QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok
)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.title_le)
lay.addWidget(button_box)
#property
def title(self):
return self.title_le.text()
class EditMacroDialog(QtWidgets.QDialog):
def __init__(self, model, index, parent=None):
super().__init__(parent)
self._group_id = model.record(index).value("id")
self.title_le = QtWidgets.QLineEdit()
self.student_table_model = QtSql.QSqlTableModel()
self.student_table_model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
self.student_table_model.setTable("Student")
self.student_table_model.setFilter("group_id={}".format(self.group_id))
self.student_table_model.select()
self.table_view = QtWidgets.QTableView(selectionBehavior=QtWidgets.QAbstractItemView.SelectRows)
self.table_view.setModel(self.student_table_model)
self.table_view.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
for name in ("group_id", "id"):
self.table_view.hideColumn(self.student_table_model.record().indexOf(name))
self.table_view.verticalHeader().hide()
self.plus_button = QtWidgets.QPushButton(self.tr("+"))
self.minus_button = QtWidgets.QPushButton(self.tr("-"))
self.save_button = QtWidgets.QPushButton(self.tr("Save"))
mapper = QtWidgets.QDataWidgetMapper(
self, submitPolicy=QtWidgets.QDataWidgetMapper.ManualSubmit
)
mapper.setModel(model)
mapper.addMapping(self.title_le, model.record().indexOf("group_name"))
mapper.setCurrentIndex(index)
self.plus_button.clicked.connect(self.addRow)
self.minus_button.clicked.connect(self.removeRow)
self.save_button.clicked.connect(mapper.submit)
self.save_button.clicked.connect(self.accept)
hlay = QtWidgets.QHBoxLayout(self)
vlay = QtWidgets.QVBoxLayout()
vlay.addWidget(self.title_le)
vlay.addWidget(self.table_view)
hlay.addLayout(vlay)
vlay2 = QtWidgets.QVBoxLayout()
vlay2.addWidget(self.plus_button)
vlay2.addWidget(self.minus_button)
vlay2.addWidget(self.save_button)
hlay.addLayout(vlay2)
#property
def group_id(self):
return self._group_id
#QtCore.pyqtSlot()
def addRow(self):
r = self.student_table_model.record()
r.setValue("group_id", self.group_id)
if self.student_table_model.insertRecord(
self.student_table_model.rowCount(), r
):
self.student_table_model.select()
#QtCore.pyqtSlot()
def removeRow(self):
ixs = self.table_view.selectionModel().selectedIndexes()
if ixs:
self.student_table_model.removeRow(ixs[0].row())
self.student_table_model.select()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self._model = QtSql.QSqlTableModel(self)
self.model.setTable("Groups")
self.model.select()
self.sql_list_view = QtWidgets.QListView()
self.sql_list_view.setModel(self.model)
self.sql_list_view.setModelColumn(self.model.record().indexOf("group_name"))
self.new_button = QtWidgets.QPushButton(self.tr("New"))
self.edit_button = QtWidgets.QPushButton(self.tr("Edit"))
self.remove_button = QtWidgets.QPushButton(self.tr("Remove"))
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
grid_layout = QtWidgets.QGridLayout(central_widget)
grid_layout.addWidget(
QtWidgets.QLabel(self.tr("Groups"), alignment=QtCore.Qt.AlignCenter)
)
grid_layout.addWidget(self.sql_list_view, 1, 0)
vlay = QtWidgets.QVBoxLayout()
vlay.addWidget(self.new_button)
vlay.addWidget(self.edit_button)
vlay.addWidget(self.remove_button)
grid_layout.addLayout(vlay, 1, 1)
self.resize(640, 480)
self.new_button.clicked.connect(self.new)
self.edit_button.clicked.connect(self.edit)
self.remove_button.clicked.connect(self.remove)
self.sql_list_view.selectionModel().selectionChanged.connect(
self.onSelectionChanged
)
self.onSelectionChanged()
#property
def model(self):
return self._model
#QtCore.pyqtSlot()
def new(self):
d = AddGroupDialog()
if d.exec_() == QtWidgets.QDialog.Accepted:
r = self.model.record()
r.setValue("group_name", d.title)
if self.model.insertRecord(self.model.rowCount(), r):
self.model.select()
#QtCore.pyqtSlot()
def edit(self):
ixs = self.sql_list_view.selectionModel().selectedIndexes()
if ixs:
d = EditMacroDialog(self.model, ixs[0].row())
d.exec_()
#QtCore.pyqtSlot()
def remove(self):
ixs = self.sql_list_view.selectionModel().selectedIndexes()
if ixs:
row = ixs[0].row()
id_ = self.model.record(row).value("id")
query = QtSql.QSqlQuery()
query.prepare("DELETE FROM Student WHERE group_id = ?")
query.addBindValue(id_)
if not query.exec_():
print(query.lastError().text())
return
self.model.removeRow(row)
self.model.select()
#QtCore.pyqtSlot()
def onSelectionChanged(self):
state = bool(self.sql_list_view.selectionModel().selectedIndexes())
self.edit_button.setEnabled(state)
self.remove_button.setEnabled(state)
if __name__ == "__main__":
import sys
database = "database.db" # ":memory:"
app = QtWidgets.QApplication(sys.argv)
if not create_connection(database):
sys.exit(app.exec_())
w = MainWindow()
w.show()
sys.exit(app.exec_())
I am using PyQt5, where I am trying to create teams and work on a league system.
I have created Action Buttons which open Dialog boxes.
I want to populate certain lists from the database based on a team name I choose from my dialog window.
I think I am stuck, because I cannot understand how to communicate between the two.
When I try to add a new team, I want that all lists in my main window get appropriately filled. But how do I pass this information from the dialog box to the main window and also close the dialog box immediately after that?
Here is the code:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QInputDialog, QLineEdit, QDialog, QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QApplication, QComboBox
import sqlite3
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
#removed because too big
#full code in link
def setupEvents(self, MainWindow):
self.actionNew_Team.triggered.connect(self.newTeam)
self.actionOpen_Team.triggered.connect(self.openTeam)
def newTeam(self, MainWindow):
n = NewTeamDialog()
n.exec_()
def openTeam(self, MainWindow):
o = OpenTeamDialog()
o.exec_()
def saveTeam(self, MainWindow):
pass
class NewTeamDialog(QDialog):
def __init__(self):
super(NewTeamDialog, self).__init__()
self.setWindowTitle("Create New Team")
self.setFixedWidth(300)
self.setFixedHeight(100)
self.nameInput = QLineEdit()
self.nameInput.setPlaceholderText("Enter Team Name")
self.addBtn = QPushButton()
self.addBtn.setText("Add Team")
self.addBtn.clicked.connect(self.addTeam)
layout = QVBoxLayout()
layout.addWidget(self.nameInput)
layout.addWidget(self.addBtn)
self.setLayout(layout)
def addTeam(self):
name = self.nameInput.text()
conn = sqlite3.connect("example.db")
c = conn.cursor()
c.execute('SELECT * FROM batsmen')
print(c.fetchall())
conn.close()
self.close()
LINK: https://www.paste.org/99817
Is this what you are looking for?
You are creating the OpenTeamDialog and NewTeamDialog classes through methods, but the dialogs don't know anything about the Window class so you must pass it as a parameter when initializing them so that you can access all of its widgets.
This is assuming that your databse is the same meaning there are the following tables:
ALLROUNDERS, BATSMEN,BOWLERS, WICKETKEEPER and a field column called TEAM:
Also I am setting up the UI in another class so I would delete any thing besides the UI part that you got from QtDesigner in the Ui_MainWindow class.
There is most likely a better way to implement this but this is just a crude design based on your needs.
class Window(QtWidgets.QMainWindow,Ui_MainWindow):
def __init__(self, parent = None):
super().__init__(parent)
self.setupUi(self)
self.setupEvents()
def setupEvents(self):
self.actionNew_Team.triggered.connect(self.newTeam)
self.actionOpen_Team.triggered.connect(self.openTeam)
def newTeam(self):
n = NewTeamDialog(self)
n.exec_()
def openTeam(self):
o = OpenTeamDialog(self)
o.exec_()
def saveTeam(self):
pass
class NewTeamDialog(QtWidgets.QDialog):
def __init__(self,window,parent = None):
super(NewTeamDialog, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.window = window
self.setWindowTitle("Create New Team")
self.setFixedWidth(300)
self.setFixedHeight(100)
self.dropDown_TeamType = QtWidgets.QComboBox()
#Added dropdown to choose which team goes in the team type
self.dropDown_TeamType.addItems(["ALLROUNDERS", "BATSMEN", "BOWLERS","WICKETKEEPER" ])
self.nameInput = QtWidgets.QLineEdit()
self.nameInput.setPlaceholderText("Enter Team Name")
self.addBtn = QtWidgets.QPushButton()
self.addBtn.setText("Add Team")
self.addBtn.clicked.connect(self.addTeam)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.dropDown_TeamType)
layout.addWidget(self.nameInput)
layout.addWidget(self.addBtn)
self.setLayout(layout)
def addTeam(self):
name = self.nameInput.text()
team_type = self.dropDown_TeamType.currentText()
conn = sqlite3.connect("example.db")
c = conn.cursor()
#adds team to the database using the current selected dropdown item
c.execute("SELECT TEAM FROM {0} WHERE TEAM=?;".format(team_type),(name.title(),))
exists = c.fetchall()
if not exists:
c.execute("INSERT INTO {0} VALUES('{1}');".format(team_type,name.title()))
conn.commit()
conn.close()
conn.close()
self.close()
if team_type == "BATSMEN":
item = QtWidgets.QListWidgetItem(name)
self.window.listWidget_3.addItem(item)
elif team_type == "ALLROUNDERS":
item = QtWidgets.QListWidgetItem(name)
self.window.listWidget_4.addItem(item)
elif team_type == "BOWLERS":
item = QtWidgets.QListWidgetItem(name)
self.window.listWidget_5.addItem(item)
elif team_type == "WICKETKEEPER":
item = QtWidgets.QListWidgetItem(name)
self.window.listWidget_6.addItem(item)
class OpenTeamDialog(QtWidgets.QDialog):
def __init__(self, window, parent = None):
super(OpenTeamDialog, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.window = window
self.setWindowTitle("Open Saved Team")
self.setFixedWidth(300)
self.setFixedHeight(100)
self.dropDown_TeamType = QtWidgets.QComboBox()
self.dropDown_TeamType.addItems(["ALLROUNDERS", "BATSMEN", "BOWLERS","WICKETKEEPER" ])
self.dropDown = QtWidgets.QComboBox()
self.dropDown_TeamType.currentIndexChanged.connect(self.itemChanged)
self.addBtn = QtWidgets.QPushButton()
self.addBtn.setText("Add Team")
self.addBtn.clicked.connect(self.openTeam)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.dropDown_TeamType)
layout.addWidget(self.dropDown)
layout.addWidget(self.addBtn)
self.setLayout(layout)
conn = sqlite3.connect("example.db")
conn.row_factory = lambda cursor, row: row[0]
c = conn.cursor()
c.execute("SELECT TEAM FROM ALLROUNDERS")
result = c.fetchall()
self.dropDown.addItems(result)
def itemChanged(self):
#adds all items from the database 'Team' column to drop down whenever it changes
team_type = self.dropDown_TeamType.currentText()
self.dropDown.clear()
conn = sqlite3.connect("example.db")
conn.row_factory = lambda cursor, row: row[0]
c = conn.cursor()
c.execute("SELECT TEAM FROM {0}".format(team_type))
result = c.fetchall()
self.dropDown.addItems(result)
conn.close()
def openTeam(self):
team_type = self.dropDown_TeamType.currentText()
team_name = self.dropDown.currentText()
self.close()
if team_type == "BATSMEN":
item = QtWidgets.QListWidgetItem(team_name)
self.window.listWidget_3.addItem(item)
elif team_type == "ALLROUNDERS":
item = QtWidgets.QListWidgetItem(team_name)
self.window.listWidget_4.addItem(item)
elif team_type == "BOWLERS":
item = QtWidgets.QListWidgetItem(team_name)
self.window.listWidget_5.addItem(item)
elif team_type == "WICKETKEEPER":
item = QtWidgets.QListWidgetItem(team_name)
self.window.listWidget_6.addItem(item)
class EvaluateDialog(QtWidgets.QDialog):
pass
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
MainWindow = Window()
MainWindow.show()
sys.exit(app.exec_())
Here is a .py file you can use to create the same database:
import sqlite3
def createTables():
connection = sqlite3.connect("example.db")
connection.execute("CREATE TABLE ALLROUNDERS(TEAM TEXT NOT NULL)")
connection.execute("CREATE TABLE BATSMEN(TEAM TEXT NOT NULL)")
connection.execute("CREATE TABLE BOWLERS(TEAM TEXT NOT NULL)")
connection.execute("CREATE TABLE WICKETKEEPER(TEAM TEXT NOT NULL)")
connection.execute("INSERT INTO ALLROUNDERS VALUES(?)",('Empty',))
connection.execute("INSERT INTO BATSMEN VALUES(?)",('Empty',))
connection.execute("INSERT INTO BOWLERS VALUES(?)",('Empty',))
connection.execute("INSERT INTO WICKETKEEPER VALUES(?)",('Empty',))
connection.commit()
result = connection.execute("SELECT * FROM BATSMEN")
connection.close()
createTables()
I am doing a image viewer pyqt gui application with sqlite3 database. But I am not able to upload images to the database. how can I do this?
def open(ui):
fname = QFileDialog.getOpenFileName(ui, 'Open file','c:\\',"Image files (*.jpg *.gif)")
ui.FirmEditLogoEntry.setText(fname)
I am able to get file name. But can’t convert to binary.
Please Help me to do this.
Thanks
With the QFileDialog you only get the name of the file, you must use that information to read the bytes of the file for it use QFile and save that data in BLOBs. In the next part I show an example:
import sys
from PyQt4.QtGui import *
from PyQt4.QtSql import *
from PyQt4.QtCore import *
def createConnection():
db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName(':memory:')
if not db.open():
QMessageBox.critical(None, "Cannot open database",
"Unable to establish a database connection.\n"
"This example needs SQLite support. Please read the Qt SQL "
"driver documentation for information how to build it.\n\n"
"Click Cancel to exit.",
QMessageBox.Cancel)
return False
query = QSqlQuery()
return query.exec_('''CREATE TABLE IF NOT EXISTS imgTable
(id INTEGER primary key AUTOINCREMENT, filename TEXT, imagedata BLOB)''')
class Widget(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
vbox = QVBoxLayout(self)
self.load_btn = QPushButton("Select Image")
self.combo = QComboBox()
self.label = QLabel()
self.model = QSqlTableModel()
self.model.setTable("imgTable")
self.model.select()
self.combo.setModel(self.model)
self.combo.setModelColumn(1)
vbox.addWidget(self.load_btn)
vbox.addWidget(self.combo)
vbox.addWidget(self.label)
self.load_btn.clicked.connect(self.load_image)
self.combo.currentIndexChanged.connect(self.on_change_select)
def on_change_select(self, row):
ix = self.combo.model().index(row, 2)
pix = QPixmap()
pix.loadFromData(ix.data())
self.label.setPixmap(pix)
def load_image(self):
fname = QFileDialog.getOpenFileName(self, 'Open file', QDir.currentPath(), "Image files (*.jpg, *.gif, *.png)")
if fname:
self.saveImage(fname)
def saveImage(self, filename):
file = QFile(filename)
if not file.open(QIODevice.ReadOnly):
return
ba = file.readAll()
name = QFileInfo(filename).fileName()
record = self.model.record()
record.setValue("filename", name)
record.setValue("imagedata", ba)
if self.model.insertRecord(-1, record):
self.model.select()
if __name__ == '__main__':
app = QApplication(sys.argv)
if not createConnection():
sys.exit(-1)
w = Widget()
w.show()
sys.exit(app.exec_())
I'm creating a GUI in PyQT5 that should provide multiple views on data from multiple related SQLite tables. I have implemented these views to be displayed via a QStackedWidget.
Now, some of these views are for overview purposes, others for more detailled views on a subset of the data displayed in the overviews. I want to access the detailled views from the overviews via rightclick.
I have included a minimal example with cars below. (Sorry, it's a bit long, but that was needed to provide a full working example. I have reduced it as much as I could.) The goal is to show the DetailledView with the cars of the company selected in the Overview.
This already provides access from the Overview to the DetailledView on Rightclick, but the company information is not passed along. So even when accessing the DetailledView from 'VW', self.mycompany gets updated but car_widget doesn't, so the DetailledView shows the info about 'Honda' cars (the default).
Is there a way to update car_widgit with the right company? Or do I need to create the DetailledView at runtime? (Does that even work? But I would prefer not to, anyway, as it could make the index of the Stack unreliable...)
How can I update the QTableModel of one view in a QStackedWidget according to what was selected in another view?
Here's the code:
#!/usr/bin/python3
from PyQt5 import QtSql
from PyQt5.QtWidgets import (QMainWindow, QWidget, QApplication, QGridLayout,
QStackedWidget, QTableView, QMenu)
from PyQt5.QtCore import Qt, QModelIndex
import sys
class MainGUI(QMainWindow):
def __init__(self):
super().__init__()
self.mycompany = "Honda"
self.create_connection()
self.fill_tables()
self.init_UI()
def create_connection(self):
self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("test.db")
if not self.db.open():
print("Cannot establish a database connection to {}!".format(self.db_file))
return False
def fill_tables(self):
self.db.transaction()
q = QtSql.QSqlQuery()
q.exec_("DROP TABLE IF EXISTS Manufacturers;")
q.exec_("CREATE TABLE Manufacturers (CompanyId INT PRIMARY KEY, Name TEXT, Country TEXT);")
q.exec_("INSERT INTO Manufacturers VALUES (1, 'VW', 'Germany');")
q.exec_("INSERT INTO Manufacturers VALUES (2, 'Honda' , 'Japan');")
q.exec_("DROP TABLE IF EXISTS Cars;")
q.exec_("CREATE TABLE Cars (Model TEXT, Year INT, Company INT);")
q.exec_("INSERT INTO Cars VALUES ('Civic', 2009, 'Honda');")
q.exec_("INSERT INTO Cars VALUES ('Golf', 2013, 'VW');")
q.exec_("INSERT INTO Cars VALUES ('Polo', 1999, 'VW');")
self.db.commit()
def init_UI(self):
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.grid = QGridLayout()
self.central_widget.setLayout(self.grid)
self.setLayout(self.grid)
self.make_stack()
self.show()
def make_stack(self):
self.Stack = QStackedWidget(self)
company_view = QWidget()
layout = QGridLayout()
company_view.setLayout(layout)
self.company_widget = Overview()
layout.addWidget(self.company_widget, 0, 0)
self.company_widget.table.customContextMenuRequested.connect(self.open_menu)
self.Stack.addWidget(company_view)
car_view = QWidget()
layout2 = QGridLayout()
car_view.setLayout(layout2)
car_widget = DetailedView(self.mycompany)
layout2.addWidget(car_widget, 0, 0)
self.Stack.addWidget(car_view)
self.grid.addWidget(self.Stack, 0,1)
def open_menu(self, pos):
menu = QMenu()
show_act = menu.addAction("Show cars")
action = menu.exec_(self.company_widget.table.mapToGlobal(pos))
if action == show_act:
row = self.company_widget.table.indexAt(pos).row()
myindex = self.company_widget.model.index(row, 1, QModelIndex())
company = self.company_widget.model.data(myindex)
self.mycompany = company
self.Stack.setCurrentIndex(1)
class MyTable(QWidget):
def __init__(self):
super().__init__()
self.create_connection()
self.create_model()
self.init_UI()
def create_connection(self):
self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("test.db")
if not self.db.open():
print("Cannot establish a database connection to {}!".format(self.db_file))
return False
def create_model(self):
self.model = None
def init_UI(self):
self.grid = QGridLayout()
self.setLayout(self.grid)
self.table = QTableView()
self.table.setModel(self.model)
self.table.setContextMenuPolicy(Qt.CustomContextMenu)
self.grid.addWidget(self.table, 0, 0)
def closeEvent(self, e):
if (self.db.open()):
self.db.close()
def check_error(self, q):
lasterr = q.lastError()
if lasterr.isValid():
print(lasterr.text())
self.db.close()
exit(1)
class Overview(MyTable):
def __init__(self):
super().__init__()
def create_model(self):
self.model = QtSql.QSqlTableModel()
q = QtSql.QSqlQuery()
query = "SELECT * from Manufacturers"
q.exec_(query)
self.model.setQuery(q)
class DetailedView(MyTable):
def __init__(self, company):
self.company = company
super().__init__()
def create_model(self):
self.model = QtSql.QSqlTableModel()
q = QtSql.QSqlQuery()
query = "SELECT * from cars where company = '{}'".format(self.company)
q.exec_(query)
self.model.setQuery(q)
def main():
app = QApplication(sys.argv)
ex = MainGUI()
ex.show()
result = app.exec_()
sys.exit(result)
if __name__ == '__main__':
main()
One of the objectives of the inheritance is that the class implements the common tasks that the children can do, and in your case you do not observe those tasks, for example the creation of the model must be done in the father since all the children will do it.
On the other hand the goal of using QSqlTableModel is not to use the QSqlQuery but more friendly requests like setTable(), select() and setFilter(), but it is simply a waste because you could use QSqlQueryModel.
On the other hand I see that you are assuming that the self.mycompany of MainGui is the same as the self.company of DetailedView for what you are going through in the creation of the DetailView object, and the truth is that they are not the same, in the creation of the object only the value of that moment has been copied, so if you change the self.company of MainGui it will not change the self.company of DetailView.
Restructuring your project you get the following:
#!/usr/bin/python3
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlTableModel
from PyQt5.QtWidgets import (QMainWindow, QWidget, QApplication, QVBoxLayout,
QStackedWidget, QTableView, QMenu)
from PyQt5.QtCore import Qt, QModelIndex, pyqtSignal
import sys
DB_PATH = "test.db"
def create_connection():
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(DB_PATH)
if not db.open():
print("Cannot establish a database connection to {}!".format(DB_PATH))
return False
return True
def fill_tables():
q = QSqlQuery()
q.exec_("DROP TABLE IF EXISTS Manufacturers;")
q.exec_("CREATE TABLE Manufacturers (CompanyId INT PRIMARY KEY, Name TEXT, Country TEXT);")
q.exec_("INSERT INTO Manufacturers VALUES (1, 'VW', 'Germany');")
q.exec_("INSERT INTO Manufacturers VALUES (2, 'Honda' , 'Japan');")
q.exec_("DROP TABLE IF EXISTS Cars;")
q.exec_("CREATE TABLE Cars (Model TEXT, Year INT, Company INT);")
q.exec_("INSERT INTO Cars VALUES ('Civic', 2009, 'Honda');")
q.exec_("INSERT INTO Cars VALUES ('Golf', 2013, 'VW');")
q.exec_("INSERT INTO Cars VALUES ('Polo', 1999, 'VW');")
class MainGUI(QMainWindow):
def __init__(self):
super().__init__()
self.init_UI()
def init_UI(self):
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.lay = QVBoxLayout(self.central_widget)
self.make_stack()
def make_stack(self):
self.stack = QStackedWidget()
self.lay.addWidget(self.stack)
self.company_widget = Overview()
self.car_widget = DetailedView()
self.stack.addWidget(self.company_widget)
self.stack.addWidget(self.car_widget)
self.company_widget.changedCompany.connect(self.changedCompany)
self.car_widget.backSignal.connect(lambda: self.stack.setCurrentIndex(0))
def changedCompany(self, company):
self.car_widget.filter(company)
self.stack.setCurrentIndex(1)
class SQLTable(QTableView):
def __init__(self, table):
super().__init__()
self.init_UI()
self.create_model(table)
def create_model(self, table):
self.model.setTable(table)
self.model.select()
def init_UI(self):
self.model = QSqlTableModel()
self.setModel(self.model)
self.setContextMenuPolicy(Qt.CustomContextMenu)
class Overview(SQLTable):
changedCompany = pyqtSignal(str)
def __init__(self):
SQLTable.__init__(self, "Manufacturers")
self.customContextMenuRequested.connect(self.open_menu)
def open_menu(self, pos):
menu = QMenu()
show_act = menu.addAction("Show cars")
action = menu.exec_(self.mapToGlobal(pos))
if action == show_act:
row = self.indexAt(pos).row()
ix = myindex = self.model.index(row, 1)
company = self.model.data(ix)
self.changedCompany.emit(company)
class DetailedView(SQLTable):
backSignal = pyqtSignal()
def __init__(self):
SQLTable.__init__(self, "cars")
self.customContextMenuRequested.connect(self.open_menu)
def open_menu(self, pos):
menu = QMenu()
back_act = menu.addAction("Show Manufacturers")
action = menu.exec_(self.mapToGlobal(pos))
if action == back_act:
self.backSignal.emit()
def filter(self, company):
self.model.setFilter("company='{}'".format(company))
def main():
app = QApplication(sys.argv)
if not create_connection():
sys.exit(-1)
fill_tables()
ex = MainGUI()
ex.show()
result = app.exec_()
sys.exit(result)
if __name__ == '__main__':
main()