Program quit with error when using QCompleter - python

I'm writing a program with pyqt5 and want to make the QlineEdit show history input by using sqlite to store the inputs. I use a signal to catch the cursor when focusInEvent happens and select the history records at that time, then I put the results into QCompleter so it can pop up in QlineEdit. Now I can make the history inputs show in QlineEdit object but when I click on any value, 1s later, the whole program quit automatically with error, which says "Python has stopped".
class FocusLineEdit(QLineEdit):
ac = pyqtSignal(list)
def __init__(self, parent=None):
super(FocusLineEdit, self).__init__(parent)
self.ac.connect(self.addCompleter)
def focusInEvent(self, event):
rtl = call_history(self.objectName())
self.ac.emit(rtl)
def addCompleter(self, rtl):
self.autoCompleter = QCompleter(rtl)
self.autoCompleter.setCompletionMode(1)
self.setCompleter(self.autoCompleter)
def focusOutEvent(self, event):
pass

It is difficult to analyze where the problem is without you provide an MCVE, so my response implements what you require without taking into account your current code for it must meet the following requirements:
You must have 2 tables: objects and history that are related.
The table objects saves the name of the filtering history, it is similar to the use of the objectName that you use, but in general 2 widgets can access the same history if the connection establishes the same name
In the history table the information of the words associated with the id of the objects table is saved.
In my example I use the following instructions to create them:
CREATE TABLE IF NOT EXISTS objects (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE);
CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY AUTOINCREMENT, id_object INTEGER REFERENCES objects (id), word TEXT NOT NULL, UNIQUE (id_object, word));
Also to test it I created a data, if you already have data then you must eliminate the if test: and everything inside.
Finally for a better understanding of my solution I show a QTableView that is changing according to the selection.
from PyQt5 import QtCore, QtGui, QtWidgets, QtSql
def createConnection():
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db_path = 'test.db'
db.setDatabaseName(db_path)
if not db.open():
QMessageBox.critical(None, qApp.tr("Cannot open database"),
qApp.tr("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
test = True
if test:
query = QtSql.QSqlQuery()
if not query.exec_('CREATE TABLE IF NOT EXISTS objects (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE);'):
return False
if not query.exec_('CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY AUTOINCREMENT, id_object INTEGER REFERENCES objects (id), word TEXT NOT NULL, UNIQUE (id_object, word));'):
return False
for i in range(3):
query.prepare('INSERT INTO objects (name) VALUES (?)')
query.addBindValue("obj{}".format(i))
if not query.exec_():
print(query.lastError().text())
import requests
import random
word_site = "http://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain"
response = requests.get(word_site)
WORDS = response.content.decode().splitlines()
print(WORDS)
for i in range(3):
for text in random.sample(WORDS, 50):
query.prepare('INSERT INTO history (id_object, word) VALUES (?, ?)')
query.addBindValue(i+1)
query.addBindValue(text)
if not query.exec_():
print(query.lastError().text())
return True
class Completer(QtWidgets.QCompleter):
def __init__(self, parent=None):
super(Completer, self).__init__(parent)
self._last_words = []
def splitPath(self, path):
if path[-1] != ' ':
words = path.split()
self._last_words = words[:-1] if len(words) > 1 else []
return [words[-1]]
else:
QtCore.QTimer.singleShot(0, self.popup().hide)
return []
def pathFromIndex(self, index):
val = super(Completer, self).pathFromIndex(index)
return ' '.join(self._last_words + [val])
class HistoryManager(QtCore.QObject):
nameChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(HistoryManager, self).__init__(parent)
model = QtSql.QSqlRelationalTableModel(self)
model.setTable("history")
model.setRelation(1, QtSql.QSqlRelation("objects", "id", "name"))
model.select()
self._proxy = QtCore.QSortFilterProxyModel(self)
self._proxy.setSourceModel(model)
self._proxy.setFilterKeyColumn(1)
# proxy.setFilterFixedString("obj1")
self._widgets = {}
self._completer = Completer(self)
self._completer.setModel(self._proxy)
self._completer.setCompletionColumn(2)
def register_widget(self, widget, objectname):
# TODO
if callable(getattr(widget, "setCompleter")):
widget.installEventFilter(self)
self._widgets[widget] = objectname
return True
return False
def eventFilter(self, obj, event):
if obj in self._widgets:
if event.type() == QtCore.QEvent.FocusIn:
name = self._widgets[obj]
self._proxy.setFilterFixedString(name)
obj.setCompleter(self._completer)
self.nameChanged.emit(name)
elif event.type() == QtCore.QEvent.FocusOut:
obj.setCompleter(None)
self._proxy.setFilterFixedString("")
self.nameChanged.emit("")
return super(HistoryManager, self).eventFilter(obj, event)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self._manager = HistoryManager()
model = QtSql.QSqlRelationalTableModel(self)
model.setTable("history")
model.setRelation(1, QtSql.QSqlRelation("objects", "id", "name"))
model.select()
self._proxy = QtCore.QSortFilterProxyModel(self)
self._proxy.setSourceModel(model)
self._proxy.setFilterKeyColumn(1)
tv = QtWidgets.QTableView()
tv.setModel(self._proxy)
vlay = QtWidgets.QVBoxLayout()
for i in range(3):
le = QtWidgets.QLineEdit()
vlay.addWidget(le)
self._manager.register_widget(le, "obj{}".format(i))
vlay.addStretch()
lay = QtWidgets.QHBoxLayout(self)
lay.addWidget(tv, stretch=1)
lay.addLayout(vlay)
self._manager.nameChanged.connect(self._proxy.setFilterFixedString)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
if not createConnection():
sys.exit(-1)
manager = HistoryManager()
w = Widget()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())

Related

How to set value to NULL in editable QTableView with QSqlTableModel

I have a QTableView that displays subset of the data from a table in SQLite database. The table is editable only for nullable numeric columns. I created two delegates - one for read-only columns:
class ReadOnlyDelegate(QtWidgets.QItemDelegate):
def editorEvent(self, *args, **kwargs):
return False
def createEditor(self, *args, **kwargs):
return None
and one for editable columns:
class LabelDelegate(QtWidgets.QItemDelegate):
def createEditor(self, parent, options, index):
self.le = QtWidgets.QLineEdit(parent)
return self.le
The table is fed by customized QSqlTableModel, where I overwrite submitAll method:
class MySqlTableModel(QtSql.QSqlTableModel):
def submitAll(self):
for row in range(self.rowCount()):
for col in range(self.columnCount()):
if self.isDirty(self.index(row, col)):
val = self.record(row).value(col)
if val == '':
self.record(row).setNull(col)
else:
try:
self.record(row).setValue(col, float(val))
except (TypeError, ValueError):
display_error_msg('Can not convert to float',
f'The value {val} could not be converted to float')
raise
super().submitAll()
Expected behaviour is (1) to convert values to float before sending to database, (2) reject inputs that can't be converted to float and (3) to convert empty string to NULL. (1) and (2) work as expected, however the last bit is not working. When debugging method .submitAll() it raises no exception on the line self.record(row).setNull(col) but it also seems to have no effect. An empty string is sent and persisted in database. Any ideas why and how to fix it?
I don't see the need to override the submitAll() method, instead you can implement the logic in the setModelData() method:
import sys
from PySide2 import QtCore, QtWidgets, QtSql
TABLENAME = "t1"
def create_connection():
db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("database.db")
if not db.open():
QtWidgets.QMessageBox.critical(
None,
QtWidgets.QApplication.instance().tr("Cannot open database"),
QtWidgets.QApplication.instance().tr(
"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."
),
QtWidgets.QMessageBox.Cancel,
)
return False
if TABLENAME in db.tables():
return True
query = QtSql.QSqlQuery()
if not query.exec_(f"CREATE TABLE IF NOT EXISTS {TABLENAME}(a REAL, b text);"):
print(query.lastError().text())
queries = (
f"INSERT INTO {TABLENAME} VALUES(1, '1');",
f"INSERT INTO {TABLENAME} VALUES(NULL, '2');",
f"INSERT INTO {TABLENAME} VALUES(3, '3');",
f"INSERT INTO {TABLENAME} VALUES(NULL, '4');",
f"INSERT INTO {TABLENAME} VALUES(5, '4');",
f"INSERT INTO {TABLENAME} VALUES(NULL, '5');",
f"INSERT INTO {TABLENAME} VALUES(NULL, '7');",
)
for query in queries:
q = QtSql.QSqlQuery()
if not q.exec_(query):
print(q.lastError().text(), query)
return False
return True
class ReadOnlyDelegate(QtWidgets.QStyledItemDelegate):
def editorEvent(self, *args, **kwargs):
return False
def createEditor(self, *args, **kwargs):
return None
class LabelDelegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, options, index):
le = QtWidgets.QLineEdit(parent)
return le
def setModelData(self, editor, model, index):
value = editor.text()
if not value:
model.setData(index, None, QtCore.Qt.EditRole)
else:
try:
number = float(value)
except (TypeError, ValueError):
print(
f"Can not convert to float, The value {value} could not be converted to float'"
)
else:
model.setData(index, number, QtCore.Qt.EditRole)
def main(args):
app = QtWidgets.QApplication(args)
if not create_connection():
sys.exit(-1)
view = QtWidgets.QTableView()
model = QtSql.QSqlTableModel()
model.setTable(TABLENAME)
model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
model.select()
view.setModel(model)
label_delegate = LabelDelegate(view)
view.setItemDelegateForColumn(0, label_delegate)
readonly_delegate = ReadOnlyDelegate(view)
view.setItemDelegateForColumn(1, readonly_delegate)
button = QtWidgets.QPushButton("Submit all")
widget = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(widget)
lay.addWidget(button)
lay.addWidget(view)
widget.resize(640, 480)
widget.show()
button.clicked.connect(model.submitAll)
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main(sys.argv)
Tested on Linux with:
PyQt5 5.15.4
PySide2 5.15.2
Python 3.9.4

Implementing setEditStrategy in editable QSqlQueryModel

This is a follow-up to this question. In there, we created an editable subclass of QSqlQueryModel, to use with complex queries.
Now I need to add a functionality like QTableModel's setEditStrategy so I can cache all changes and accept or revert them using buttons. PyQt apparently doesn't allow multiple inheritance and I cannot find sufficient documentation to re-implement this method in my custom model, therefor here's the question:
How can I re-implement QSqlTableModel.setEditStragety (or something like it) including RevertAll() and SubmitAll() in an editable QSqlQueryModel?
Here's a CVME: (I have out-commented the parts of of my Example class I would like to get working)
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel, QSqlTableModel
from PyQt5.QtWidgets import QApplication, QTableView, QWidget, QGridLayout
from PyQt5.Qt import QPushButton
db_file = "test.db"
def create_connection(file_path):
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(file_path)
if not db.open():
print("Cannot establish a database connection to {}!".format(file_path))
return False
return True
def fill_tables():
q = QSqlQuery()
q.exec_("DROP TABLE IF EXISTS Manufacturers;")
q.exec_("CREATE TABLE Manufacturers (Company TEXT, Country TEXT);")
q.exec_("INSERT INTO Manufacturers VALUES ('VW', 'Germany');")
q.exec_("INSERT INTO Manufacturers VALUES ('Honda' , 'Japan');")
q.exec_("DROP TABLE IF EXISTS Cars;")
q.exec_("CREATE TABLE Cars (Company TEXT, Model TEXT, Year INT);")
q.exec_("INSERT INTO Cars VALUES ('Honda', 'Civic', 2009);")
q.exec_("INSERT INTO Cars VALUES ('VW', 'Golf', 2013);")
q.exec_("INSERT INTO Cars VALUES ('VW', 'Polo', 1999);")
class SqlQueryModel_editable(QSqlQueryModel):
"""a subclass of QSqlQueryModel where individual columns can be defined as editable
"""
def __init__(self, editables):
"""editables should be a dict of format:
{INT editable_column_nr : (STR update query to be performed when changes are made on this column
INT model's column number for the filter-column (used in the where-clause),
)}
"""
super().__init__()
self.editables = editables
def flags(self, index):
fl = QSqlQueryModel.flags(self, index)
if index.column() in self.editables:
fl |= Qt.ItemIsEditable
return fl
def setData(self, index, value, role=Qt.EditRole):
if role == Qt.EditRole:
mycolumn = index.column()
if mycolumn in self.editables:
(query, filter_col) = self.editables[mycolumn]
filter_value = self.index(index.row(), filter_col).data()
q = QSqlQuery(query.format(value, filter_value))
result = q.exec_()
if result:
self.query().exec_()
else:
print(self.query().lastError().text())
return result
return QSqlQueryModel.setData(self, index, value, role)
def setFilter(self, myfilter):
text = (self.query().lastQuery() + " WHERE " + myfilter)
self.setQuery(text)
class Example(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 150)
self.createModel()
self.initUI()
def createModel(self):
editables = {1 : ("UPDATE Manufacturers SET Country = '{}' WHERE Company = '{}'", 2)}
self.model = SqlQueryModel_editable(editables)
query = '''
SELECT (comp.company || " " || cars.model) as Car,
comp.Country,
cars.company,
(CASE WHEN cars.Year > 2000 THEN 'yes' ELSE 'no' END) as this_century
from manufacturers comp left join cars
on comp.company = cars.company
'''
q = QSqlQuery(query)
self.model.setQuery(q)
self.model.setFilter("cars.Company = 'VW'")
# self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)
def initUI(self):
self.layout = QGridLayout()
self.setLayout(self.layout)
self.view = QTableView()
self.view.setModel(self.model)
self.view.hideColumn(2)
self.layout.addWidget(self.view,0,0,1,2)
self.accept_btn = QPushButton("Accept Changes")
# self.accept_btn.clicked.connect(self.model.submitAll)
self.layout.addWidget(self.accept_btn, 1,0)
self.reject_btn = QPushButton("Reject Changes")
# self.reject_btn.clicked.connect(self.model.revertAll)
self.layout.addWidget(self.reject_btn, 1,1)
if __name__ == '__main__':
app = QApplication(sys.argv)
if not create_connection(db_file):
sys.exit(-1)
fill_tables()
ex = Example()
ex.show()
sys.exit(app.exec_())
Edit to clarify:
I need an editable QSqlQueryModel, on which I can use submitAll() and revertAll(), so that changes to the model's data are only accepted after an Accept-button is clicked, or can be reverted using a "Reject" button.

PYQT: QTableView. Filter Between Dates

I've created a GUI that allows users to modify, filter update and delete from a sqlite database. Everything is working great except the date range filter. When I run the code, I don't get an error, I only get a blank filtered screen with no data. Does anyone see what's wrong with my code? [Section 1a, subgroup{v} is what I am seeking help on]. Thanks!
from PyQt4 import QtCore, QtGui, QtSql
import sys
import sqlite3
import time
import Search #imported ui.py MainWindow file
import os
try:
from PyQt4.QtCore import QString
except ImportError:
QString = str
class TableEditor(QtGui.QMainWindow, Search.Search_MainWindow):
def __init__(self, tableName, parent=None):
super(self.__class__, self).__init__()
self.setupUi(self)
self.model = QtSql.QSqlTableModel(self)
self.model.setTable('CAUTI')
self.model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
self.model.select()
self.model.setHeaderData(0, QtCore.Qt.Horizontal, "MRN")
self.model.setHeaderData(1, QtCore.Qt.Horizontal, "Last Name")
self.model.setHeaderData(2, QtCore.Qt.Horizontal, "First Name")
self.model.setHeaderData(3, QtCore.Qt.Horizontal, "Date of Event")
self.model.setHeaderData(4, QtCore.Qt.Horizontal, "Facility")
self.model.setHeaderData(5, QtCore.Qt.Horizontal, "Unit")
self.model.setHeaderData(6, QtCore.Qt.Horizontal, "User")
self.tableView.setModel(self.model)
self.setWindowTitle("HAI Table")
self.tableView.setColumnWidth(0,100)
self.tableView.setColumnWidth(1,100)
self.tableView.setColumnWidth(2,100)
self.tableView.setColumnWidth(3,100)
self.tableView.setColumnWidth(4,100)
self.tableView.setColumnWidth(5,100)
self.tableView.setColumnWidth(6,83)
self.submitButton.clicked.connect(self.submit)
self.revertButton.clicked.connect(self.model.revertAll)
self.quitButton.clicked.connect(self.close)
current = QtCore.QDateTime.currentDateTime()
self.startDate.setDate(current.date())
self.endDate.setDate(current.date())
self.startDate.setDisplayFormat("M/dd/yyyy")
self.endDate.setDisplayFormat("M/dd/yyyy")
# Section 1: Signals
# {i} Search Fields Button Emitted:
# [1]
self.search_MRN_Button.clicked.connect(self.search_MRN_FilterRecord)
# [2]
self.search_Lname_Button.clicked.connect(self.search_Lname_FilterRecord)
# [3]
self.search_Unit_Button.clicked.connect(self.search_Unit_FilterRecord)
# {ii} Search Clear Buttons Emitted:
# [1]
self.search_MRN_CancelButton.clicked.connect(self.search_MRN_CancelButton_Clicked)
# [2]
self.search_Lname_CancelButton.clicked.connect(self.search_Lname_CancelButton_Clicked)
# [3]
self.search_Unit_CancelButton.clicked.connect(self.search_Unit_CancelButton_Clicked)
# {iii} Search Fields Button Emitted:
# [1]
self.search_MRN.selectionChanged.connect(self.search_MRN_Edit)
# [2]
self.search_Lname.selectionChanged.connect(self.search_Lname_Edit)
# [3]
self.search_Unit.selectionChanged.connect(self.search_Unit_Edit)
# {iv} Search Fields Button Emitted:
# [1]
self.search_MRN.returnPressed.connect(self.search_MRN_Enter)
# [2]
self.search_Lname.returnPressed.connect(self.search_Lname_Enter)
# [3]
self.search_Unit.returnPressed.connect(self.search_Unit_Enter)
#{v} Search Between 2 Dates
self.btnSubmit.clicked.connect(self.FilterBetweenDates)
# Section 1a: Slots from Section 1.
#{i} Search Field Button Slots:
#[1]
def search_MRN_FilterRecord(self):
text = self.search_MRN.text()
if len(text) == 0:
self.model.setFilter("")
else:
self.model.setFilter("MRN like'" +self.search_MRN.text()+ "%%'")
#self.model.setFilter("MRN = '%s'" % text)
#[2]
def search_Lname_FilterRecord(self):
text = self.search_Lname.text()
if len(text) == 0:
self.model.setFilter("")
else:
self.model.setFilter("Surname like'" +self.search_Lname.text()+ "%'")
#self.model.setFilter("Surname = '%s'" % text) #This line of code will only pull exact matches.
#[3]
def search_Unit_FilterRecord(self):
text = self.search_Unit.text()
if len(text) == 0:
self.model.setFilter("")
else:
self.model.setFilter("Unit like'" +self.search_Unit.text()+ "%'")
#self.model.setFilter("Unit = '%s'" % text) #This line of code will only pull exact matches.
#{ii} Search Field Cancel Button Slots:
#[1]
def search_MRN_CancelButton_Clicked(self):
self.model.setFilter("")
self.search_MRN.setText("MRN Search")
#[2]
def search_Lname_CancelButton_Clicked(self):
self.model.setFilter("")
self.search_Lname.setText("Last Name Search")
#[3]
def search_Unit_CancelButton_Clicked(self):
self.model.setFilter("")
self.search_Unit.setText("Unit Search")
#{iii} Search Text Edited Slots:
#[1]
def search_MRN_Edit(self):
self.search_MRN.setText("")
#[2]
def search_Lname_Edit(self):
self.search_Lname.setText("")
#[3]
def search_Unit_Edit(self):
self.search_Unit.setText("")
#{iv} Search Text Return Pressed (Enter) Slots:
#[1]
def search_MRN_Enter(self):
self.search_MRN_FilterRecord()
#[2]
def search_Lname_Enter(self):
self.search_Lname_FilterRecord()
#[3]
def search_Unit_Enter(self):
self.search_Unit_FilterRecord()
#{v} Filter Between Dates, Slot:
def FilterBetweenDates(self):
start = str(self.startDate.text())
finish = str(self.endDate.text())
self.model.setFilter("EventDate BETWEEN'" + start and finish)
def submit(self):
self.model.database().transaction()
if self.model.submitAll():
self.model.database().commit()
else:
self.model.database().rollback()
QtGui.QMessageBox.warning(self, "HAI Table",
"The database reported an error: %s" % self.model.lastError().text())
def main():
app = QtGui.QApplication(sys.argv)
#app.setStyle( "Plastique" )
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('HAI.db')
editor = TableEditor('CAUTI')
editor.show()
app.exec_()
if __name__ == '__main__':
The and in your filter text should part of the filter string. Now you are taking the logical-and of two strings (which will be the last string unless the first is empty) and append that to the filter string.
So change
self.model.setFilter("EventDate BETWEEN'" + start and finish)
to
filter = "EventDate BETWEEN '{}' AND '{}'".format(start, finish)
print(filter) # for debugging
self.model.setFilter(filter)
During debugging, it's probably a good idea to print the filter string and try it out in an SQL query (directly in the sqlite3 tool) so that you can see it works.

PyQt4 How to send push button signal to another class in Python?

I need your advice and help for my code.
I am making a GUI program. Basically the program does the followings:
Gets input from the user
When a certain button is pushed, the program retrieves all the input and saved them in the database
The program does computations.
Shows the output
Here is the simple version of the program, calculator program:
As you can see in the figure, it takes 4 input from user, (1) any integer for var1, (2) any integer for var2, (3) operator (addition or subtraction) and (4) click button.
The GUI was designed using QtDesigner.
And here is my code:
import sys
import sqlite3
from PyQt4 import QtCore, QtGui
from testgui import Ui_MainWindow
class ShowAndInput(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
#connect to the database
self.connect_to_db()
#create table in the database
self.create_table()
#add items to the comboBox
self.add_items()
#calculate button to start calculating, gives signal to the next class Calculate
self.ui.pushButton_3.clicked.connect(self.calculate)
#close button to close the window
QtCore.QObject.connect(self.ui.pushButton,QtCore.SIGNAL("clicked()"), quit)
self.conn.close()
def connect_to_db(self):
self.conn = sqlite3.connect('testguidb.sqlite3')
self.cur = self.conn.cursor()
def create_table(self):
self.cur.execute('''CREATE TABLE IF NOT EXISTS Input (var1 INTEGER, var2 INTEGER)''')
self.conn.commit()
def add_items(self):
lst = ['addition', 'subtraction']
self.ui.comboBox.clear()
self.ui.comboBox.addItems(lst)
def calculate(self):
calculate = Calculate(self)
calculate.exec_()
So the purpose of the first class was to show the GUI and take input from the user. If user clicks the pushbutton named 'Calculate', it should connect to the new class named 'Calculate'.
Here is my code for the Calculate class:
class Calculate(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QWidget.__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
#validator to validate that the input is integer or digit
#connect to database
self.connect_to_db()
#get the input values and store them in the database
self.get_the_values()
#print the output
PrintOutcome()
def connect_to_db(self):
self.conn = sqlite3.connect('testguidb.sqlite3')
self.cur = self.conn.cursor()
def get_the_values(self):
dicti = {}
dicti['var1'] = self.ui.lineEdit.text()
dicti['var2'] = self.ui.lineEdit_2.text()
for key, val in sorted(dicti.items()):
key = str(key)
val = int(val)
self.cur.execute('INSERT OR IGNORE INTO Input (?) VALUES (?)',(key,val))
self.conn.commit()
And at the end of this class, it calls another class named 'PrintOutcome' to print out the result in the QTextBrowser. Here is the last piece of the code:
class PrintOutcome(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QWidget.__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
#connect to database
self.connect_to_db()
#get the value of the combobox
self.get_combox()
#print the output
if self.operator == 'addition': self.print_add()
elif self.operator == 'subtraction': self.print_sub()
def connect_to_db(self):
self.conn = sqlite3.connect('testguidb.sqlite3')
self.cur = self.conn.cursor()
def get_combox(self):
self.operator = str(self.ui.comboBox.currentText())
def print_add(self):
dicti={}
for i in range(2):
i = i + 1
dicti['var{0}'.format(i)] = self.cur.execute('SELECT var{0} FROM Input'.format(i))
dicti['var{0}'.format(i)] = int(self.cur.fetchone()[0])
text = str(dicti['var{0}'.format(i)])
self.ui.textBrowser.append(text)
result = dicti['var1'] + dicti['var2']
textsep = '-'*25+'(+)'
text = str(result)
self.ui.textBrowser.append(text)
self.ui.textBrowser.append(text)
def print_sub(self):
dicti={}
for i in range(2):
i = i + 1
dicti['var{0}'.format(i)] = self.cur.execute('SELECT var{0} FROM Input'.format(i))
dicti['var{0}'.format(i)] = int(self.cur.fetchone()[0])
text = str(dicti['var{0}'.format(i)])
self.ui.textBrowser.append(text)
result = dicti['var1'] + dicti['var2']
textsep = '-'*25+'(-)'
text = str(result)
self.ui.textBrowser.append(text)
self.ui.textBrowser.append(text)
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
myapp = ShowAndInput()
myapp.show()
sys.exit(app.exec_())
When I ran it, everything was fine. But when I pressed the calculate button, it returned an error message.
Here is the error message: RuntimeError: super-class init() of type Calculate was never called.
Any respond will be much appreciated. Thanks a lot.
Regards,
Arnold

pyqt Using QDataWidgetMapper to update row in database

I am trying to use the QDataWidgetmapper to update a row in the database but my issue is when trying to call the update function row is not a global variable and I have tried to use it in the same function that calls the Qdialog for the input int. I cannot get it to work. I have tried many variations but I am now at my wits end. I'm sure there is something simple I am missing but I am still learning python and pyqt.
import sys
from testdbtableform import *
from PyQt4 import QtSql, QtGui
def createConnection():
"""Creates the pyqt connection to the database"""
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('demo.db')
if db.open():
return True
else:
print db.lastError().text()
return False
class MyForm(QtGui.QDialog):
"""Creates the class"""
def __init__(self, parent=None):
"""Initiates the class"""
QtGui.QDialog.__init__(self, parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.model = QtSql.QSqlRelationalTableModel(self)
self.model.setTable("userlist")
self.model.setSort(0, 0)
self.model.setEditStrategy(2)
self.model.select()
self.mapper = QtGui.QDataWidgetMapper(self)
self.mapper.setSubmitPolicy(1)
self.mapper.setModel(self.model)
self.mapper.addMapping(self.ui.lineEditUser, 0)
self.mapper.addMapping(self.ui.lineEditEmail, 1)
self.ui.tableView.setModel(self.model)
self.ui.pushSearch.clicked.connect(self.dbfilter)
self.ui.Submit.clicked.connect(self.dbinput)
self.ui.pushButton.clicked.connect(self.mapindex)
self.ui.updateButton.clicked.connect(self.updaterow)
self.ui.updateButton.hide()
def mapindex(self):
"""Function called to update a row in the tableview and database"""
i, ok = QtGui.QInputDialog.getInteger(self,
"Update Row", "Row:", 1, 1, 100, 1)
row = "%d" % i
row = int(row) - 1
if ok:
self.ui.Submit.hide()
self.ui.updateButton.show()
self.mapper.setCurrentIndex(row)
def updaterow(self):
"""Function to update data from line edits to the database"""
text1 = self.ui.lineEditUser.text()
text2 = self.ui.lineEditEmail.text()
self.model.setData(self.model.index(row, 0), str(text1).upper())
self.model.setData(self.model.index(row, 1), str(text2))
self.model.submitAll()
self.ui.lineEditUser.clear()
self.ui.lineEditEmail.clear()
self.ui.Submit.show()
self.ui.updateButton.hide()
def dbinput(self):
"""Function to input data from line edits to the database"""
self.model.insertRow(0)
text1 = self.ui.lineEditUser.text()
text2 = self.ui.lineEditEmail.text()
self.model.setData(self.model.index(0, 0), str(text1).upper())
self.model.setData(self.model.index(0, 1), str(text2))
self.model.submitAll()
self.ui.lineEditUser.clear()
self.ui.lineEditEmail.clear()
def dbfilter(self):
"""Function to search through the database for the username"""
self.model.setFilter("USERNAME like '"+self.ui.lineEditSearch.text()+"%'")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
if not createConnection():
sys.exit(1)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
Alright after banging my head against a wall for a few minutes and then just watching random youtube videos on random things davidb from the pyqt irc channel asked me "Is row the same as self.mapper.currentIndex()" so I chanaged row under the update function to row = self.mapper.currentIndex() and it worked. Something simple that I was over looking because I was getting frustrated. Below are the correct functions.
def mapindex(self):
"""Function called to update a row in the tableview and database"""
i, ok = QtGui.QInputDialog.getInteger(self,
"Update Row", "Row:", 1, 1, 100, 1)
row = "%d" % i
row = int(row) - 1
if ok:
self.ui.Submit.hide()
self.ui.updateButton.show()
self.mapper.setCurrentIndex(row)
def updaterow(self):
"""Function to update data from line edits to the database"""
text1 = self.ui.lineEditUser.text()
text2 = self.ui.lineEditEmail.text()
row = self.mapper.currentIndex() #being the missing link
self.model.setData(self.model.index(row, 0), str(text1).upper())
self.model.setData(self.model.index(row, 1), str(text2))
self.model.submitAll()
self.ui.lineEditUser.clear()
self.ui.lineEditEmail.clear()
self.ui.Submit.show()
self.ui.updateButton.hide()

Categories