I have a table with some records that are keyed using a very large number as the primary key. I have code similar to the following which uses QCompleter to autocomplete lookups in this table. It works, but the displayed completions are formatted using the scientific notation (1234567 => 1.23e6). I'd like to have my completions displayed as-is. In my opinion, I'd either need to cast the response from the query as a string (can't figure out how to do this) or set a property on the QLineEdit to disable scientific notation formatting (can't figure this out either). Any ideas?
class MyDialog(BaseObject, QtGui.QDialog):
def __init__(self, ... db=None):
super(MyDialog, self).__init__(parent, logger)
self.qsql_db = db
self.init_ui()
def mk_model(self, completer, pFilterModel, table_name, filter_=None):
model = QtSql.QSqlTableModel()
model.setTable(table_name)
if filter_:
model.setFilter(filter_)
model.select()
pFilterModel.setSourceModel(model)
completer.setModel(pFilterModel)
return model
def setModelColumn(self, completer, pFilterModel, column):
completer.setCompletionColumn(column)
pFilterModel.setFilterKeyColumn(column)
def mk_receipt_id_grid(self):
font = self.mk_font()
label_receipt_id = QtGui.QLabel(self)
label_receipt_id.setText("Order ID")
label_receipt_id.setFont(font)
self.text_edit_receipt_id = QtGui.QLineEdit()
self.text_edit_receipt_id.setFont(font)
label_receipt_id.setBuddy(self.text_edit_receipt_id)
self.formGridLayout.addWidget(label_receipt_id, 0, 0)
self.formGridLayout.addWidget(self.text_edit_receipt_id, 0, 1)
self.connect(self.text_edit_receipt_id,
QtCore.SIGNAL("editingFinished()"),
self.get_order_details)
completer = QtGui.QCompleter(self)
completer.setCompletionMode(QtGui.QCompleter.UnfilteredPopupCompletion)
pFilterModel = QtGui.QSortFilterProxyModel(self)
pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
completer.setPopup(completer.popup())
self.text_edit_receipt_id.setCompleter(completer)
model = self.mk_model(completer, pFilterModel, "orders", "created_at > date_trunc('day', now())")
self.setModelColumn(completer, pFilterModel, model.fieldIndex("receipt_id"))
self.text_edit_receipt_id.textEdited.connect(pFilterModel.setFilterFixedString)
Screenshot of the issue:
One way to do this would be to set an item-delegate on the completer's view. The QStyledItemDelegate class has a displayText method that can be overridden, which makes implementing this quite easy.
Here is a simple demo:
import sys
from PySide import QtGui, QtCore
class ItemDelegate(QtGui.QStyledItemDelegate):
def displayText(self, data, locale):
if isinstance(data, (int, float)):
data = '%d' % data
return super(ItemDelegate, self).displayText(data, locale)
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
edit = QtGui.QLineEdit()
layout = QtGui.QVBoxLayout(self)
layout.addWidget(edit)
completer = QtGui.QCompleter(self)
model = QtGui.QStandardItemModel(self)
for value in (
17596767040000.0, 47993723466378568.0,
1219073478568475.0, 43726487587345.0,
29928757235623.0, 2245634345639486934.0,
):
item = QtGui.QStandardItem()
item.setData(value, QtCore.Qt.EditRole)
model.appendRow([item])
completer.setModel(model)
completer.popup().setItemDelegate(ItemDelegate(self))
edit.setCompleter(completer)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(600, 100, 300, 50)
window.show()
sys.exit(app.exec_())
Related
Using the QTDesigner I made a simple QListWidge that contains three items
Apple
Banana
Orange
My Goal, when one of those options is selected it launches a specific function. For some reason I cannot figure this out and I can't find anything within my Google searches. I am new to pyQT so maybe I'm just using the incorrect terms.
Using QT Designer I can set the SIGNAL and SLOT, but the effect is for every single item within the QListWidget, it is not specific.
Here is the code I am concerned with
QtCore.QObject.connect(self.listWidget, QtCore.SIGNAL(_fromUtf8("itemClicked(QListWidgetItem*)")), MainWindow.close)
That code is closing the main window when any QListWidgetItem is selected. I want it to only close when "apple" is selected. I want Banana and Orange to do something else.
Seems like all the examples I find online are not addressing if you want item A to do something vs item B. They all just use a generic sample in which all items do the same thing.
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'untitled.ui'
#
# Created by: PyQt4 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGuii
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(800, 600)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.listWidget = QtGui.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(50, 60, 256, 241))
self.listWidget.setObjectName(_fromUtf8("listWidget"))
item = QtGui.QListWidgetItem()
self.listWidget.addItem(item)
item = QtGui.QListWidgetItem()
self.listWidget.addItem(item)
item = QtGui.QListWidgetItem()
self.listWidget.addItem(item)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName(_fromUtf8("menubar"))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QObject.connect(self.listWidget, QtCore.SIGNAL(_fromUtf8("itemClicked(QListWidgetItem*)")), MainWindow.close)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
__sortingEnabled = self.listWidget.isSortingEnabled()
self.listWidget.setSortingEnabled(False)
item = self.listWidget.item(0)
item.setText(_translate("MainWindow", "apple", None))
item = self.listWidget.item(1)
item.setText(_translate("MainWindow", "banana", None))
item = self.listWidget.item(2)
item.setText(_translate("MainWindow", "orange", None))
self.listWidget.setSortingEnabled(__sortingEnabled)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Was able to piece together the solution using the website below and some example scripts floating around. They key to the solution was the .item
.item(0) is reviewing what is currently set at index 0. The website below showed that I could attach a .isSelected() that would return True when a list item is selected.
With both pieces of information I can now take a specific action when a specific item is selected.
http://doc.qt.io/qt-4.8/qlistwidgetitem.html#isSelected
QtCore.QObject.connect(self.listWidget, QtCore.SIGNAL(_fromUtf8("itemClicked(QListWidgetItem*)")), self.closewindow)
def closewindow(self):
apple = self.listWidget.item(0).isSelected()
banana = self.listWidget.item(1).isSelected()
if apple == True:
self.exitprogram()
elif banana == True:
print 'Banana selected'
def exitprogram(self):
sys.exit()
i have made a simple pyqt gui with QLineEdit and QPushButton. i like to add showurl(in con.py given below) to sqlite db. the code :
ui.py
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(400, 300)
self.verticalLayout_2 = QtGui.QVBoxLayout(Form)
self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
self.verticalLayout = QtGui.QVBoxLayout()
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.inserturl = QtGui.QLineEdit(Form)
self.inserturl.setObjectName(_fromUtf8("inserturl"))
self.verticalLayout.addWidget(self.inserturl)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.insertdb_btn = QtGui.QPushButton(Form)
self.insertdb_btn.setObjectName(_fromUtf8("insertdb_btn"))
self.verticalLayout.addWidget(self.insertdb_btn)
self.verticalLayout_2.addLayout(self.verticalLayout)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
self.insertdb_btn.setText(_translate("Form", "ok", None))
con.py
import sys
from PyQt4 import QtCore, QtGui, QtSql
from insertdb2_ui import Ui_Form
def createConnection():
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('webscrap.db')
if db.open():
return True
else:
print db.lastError().text()
return False
class Test(QtGui.QWidget, Ui_Form):
def __init__(self):
super(Test, self).__init__()
self.setupUi(self)
self.insertdb_btn.clicked.connect(self.onClick)
def onClick(self):
showurl = self.inserturl.text()
print showurl
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
if not createConnection():
sys.exit(1)
window = Test()
window.show()
sys.exit(app.exec_())
i made the input data ie. showurl print on terminal. i want to add the showurl to sqlitedb webscrap.db which has fields id and url.
I am also confused about using model view(QSqlTableModel, QDataWidgetMapper).
You can use the QtSql.QSqlQuery() class to create query objects that interact with your database. To execute a query (in this case, an INSERT query), perform the following steps:
Instantiate a QSqlQuery() object.
Call the prepare() method on that object, passing to the prepare() method the SQL text that you want to execute.
Use the addBindValue() method to pass in variables to your query -- in this case, you want to pass in showurl.
Finally, call exec_() on the query object to execute
the query. If there is an error, you can retrieve it by calling on
the query object lastError().text().
So, in code, you would need to change your onClick() function to:
def onClick(self):
showurl = self.inserturl.text()
query_object = QtSql.QSqlQuery()
query_object.prepare("INSERT INTO table (url) VALUES (?)")
query_object.addBindValue(showurl)
if not query_object.exec_():
print query_object.lastError().text()
Please note that I did not specify a table name to insert into because you provided field names (id and url) but not a table name; therefore the query string uses a fake table name (table). You should replace this with a real table name. If you do not have a table in your database, you need to create one. Please reference https://www.sqlite.org/lang.html for documentation on SQLite commands (e.g. for creating tables). Please also refer to the PyQt4 documentation on QtSql.QSqlQuery(): http://pyqt.sourceforge.net/Docs/PyQt4/qsqlquery.html
For QSqlTableModel and QDataWidgetMapper, it is difficult to help without having a specific question to answer about them, but I highly recommend that you check out this excellent guide to both of those classes: http://doc.qt.digia.com/qq/qq21-datawidgetmapper.html. This guide does not use PyQt4 (instead it uses Qt alone, so the code is in C++), but the code is sparse and the concepts should resonate even if you are not familiar with C++.
Sorting QTreeView with QSortFilterProxyModel is extremely slow (compared to basic QTreeWidget). What's wrong with the code? How can I speed-up?
# coding: utf-8
import sys
from PyQt5.QtWidgets import (QTreeView, QAbstractItemView,
QMainWindow, QApplication)
from PyQt5.QtSql import (QSqlDatabase, QSqlQuery, QSqlQueryModel)
from PyQt5.QtCore import QSortFilterProxyModel
class Database:
def __init__(self):
self.db = QSqlDatabase.addDatabase("QODBC")
self.db.setDatabaseName(
r'Driver={SQL Server Native Client 11.0};Server={(localdb)\v11.0};')
self.db.open()
class Model(QSqlQueryModel):
def __init__(self, parent=None):
super().__init__(parent)
query = QSqlQuery()
query.prepare('SELECT * FROM Companies WHERE Name LIKE ?')
query.bindValue(0, '%elektro%')
query.exec_()
self.setQuery(query)
class TreeView(QTreeView):
def edit(self, index, trigger, event):
if trigger == QAbstractItemView.DoubleClicked:
return False
return QTreeView.edit(self, index, trigger, event)
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.db = Database()
self.model = Model()
sortFilterModel = QSortFilterProxyModel()
sortFilterModel.setSourceModel(self.model)
treeView = TreeView(self)
treeView.setModel(sortFilterModel)
treeView.hideColumn(0)
treeView.hideColumn(9)
treeView.setIndentation(0)
treeView.setSelectionMode(QAbstractItemView.MultiSelection)
treeView.setAllColumnsShowFocus(True)
treeView.setSortingEnabled(True)
treeView.clicked.connect(self.row_id)
self.setCentralWidget(treeView)
def row_id(self, index):
if index.isValid():
id_ = index.sibling(index.row(), 0).data()
print(id_)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
app.exec_()
Some tips (from a C++ perspective, so i could be missing something )
QTreeView is known for being slower than a QTableView and consume a lot of memory And you are using a plain table model anyways, so, try with a QTableview.
Also, in a real tree hierarchical model hiding column 0 would hide all child items.
Try using QSqlTableModel instead of a QSqlQueryModel, it has convenience setSort, setFilter methods and only fetchs visible rows. So i would be probably faster.
I use GTK and Python for developing an application.
I want to load TreeView elements (1 column) from SQLite3 database.
But something go wrong (without any error)!
Here is a whole code:
#!/usr/bin/python
import sys
import sqlite3 as sqlite
from gi.repository import Gtk
from gi.repository import Notify
def notify(notifer, text, notificationtype=""):
Notify.init("Application")
notification = Notify.Notification.new (notifer, text, notificationtype)
notification.show ()
def get_object(gtkname):
builder = Gtk.Builder()
builder.add_from_file("main.ui")
return builder.get_object(gtkname)
def base_connect(basefile):
return sqlite.connect(basefile)
class Handler:
def main_destroy(self, *args):
Gtk.main_quit(*args)
def hardwaretool_clicked(self, widget):
baselist = get_object("subjectlist")
baselist.clear()
base = base_connect("subjectbase")
with base:
cur = base.cursor()
cur.execute("SELECT * FROM sub")
while True:
row = cur.fetchone()
if row == None:
break
iter = baselist.append()
print "row ", row[0]
baselist.set(iter, 0, row[0])
cur.close()
def gamestool_clicked(self, widget):
print("gamestool clicked!!!!! =)")
def appstool_clicked(self, widget):
print("appstool clicked!!!!! =)")
def fixtool_clicked(self, widget):
notify("Charmix","Fix Applied", "dialog-ok")
def brokenfixtool_clicked(self, widget):
notify("Charmix","Broken Fix Report Sended", "dialog-error")
def sendfixtool_clicked(self, widget):
notify("Charmix","Fix Sended", "dialog-information")
class CharmixMain:
def __init__(self):
builder = Gtk.Builder()
builder.add_from_file("main.ui")
self.window = builder.get_object("main")
self.subject = builder.get_object("subjectlist")
self.problem = builder.get_object("problemlist")
self.toolbar = builder.get_object("toolbar")
self.hardwaretool = builder.get_object("hardwaretool")
self.gamestool = builder.get_object("gamestool")
self.appstool = builder.get_object("appstool")
self.fixtool = builder.get_object("fixtool")
self.brokenfixtool = builder.get_object("brokenfixtool")
self.sendfixtool = builder.get_object("sendfixtool")
builder.connect_signals(Handler())
context = self.toolbar.get_style_context()
context.add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)
if __name__ == "__main__":
Charmix = CharmixMain()
Charmix.window.show()
Gtk.main()
I'm interested in this part (not working normally):
def hardwaretool_clicked(self, widget):
baselist = get_object("subjectlist")
baselist.clear()
base = base_connect("subjectbase")
with base:
cur = base.cursor()
cur.execute("SELECT * FROM sub")
while True:
row = cur.fetchone()
if row == None:
break
iter = baselist.append()
print "row ", row[0]
baselist.set(iter, 0, row[0])
cur.close()
TreeView(subjecttree) don't display anything, but print "row ", row[0] works fine and display all the strings.
Please, help me.
Maybe i need to repaint TreeView or thomething like that?
Do you know, how can I get it?
The problem is in your get_object method.
When you do:
builder = Gtk.Builder()
builder.add_from_file("main.ui")
you're actually creating a new window; even if you are using the same ui file, you are creating a completely different widget.
One way to get around the problem of accesing the widgets you need to process with your handler is to pass them as parameter of the constructor:
class Handler(object):
def __init__(self, widget1, widget2):
self.widget1 = widget1
self.widget2 = widget2
...
You can use those widgets on the handler's method afterwards.
Another way of accesing the widgets in a more 'decoupled' way is to add the object you want to use as the last parameter of the connect method when you're connecting signals; the drawback is that you would have to do this manually (since Glade doesn't provide this posibility)
self.widget.connect('some-signal', handler.handler_method, object_to_use)
I am using pyQt. How can I disable child items sorting in QTreeView/StandardItemModel?
You could use a QSortFilterProxyModel and reimplement its lessThan method.
Alternatively, create a subclass of QStandardItem and reimplement its less than operator.
Here's a simple example that demonstrates the latter approach:
from random import sample
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.view = QtGui.QTreeView(self)
self.view.setHeaderHidden(True)
self.model = QtGui.QStandardItemModel(self.view)
self.view.setModel(self.model)
parent = self.model.invisibleRootItem()
keys = range(65, 91)
for key in sample(keys, 10):
item = StandardItem('Item %s' % chr(key), False)
parent.appendRow(item)
for key in sample(keys, 10):
item.appendRow(StandardItem('Child %s' % chr(key)))
self.view.sortByColumn(0, QtCore.Qt.AscendingOrder)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.view)
class StandardItem(QtGui.QStandardItem):
def __init__(self, text, sortable=True):
QtGui.QStandardItem.__init__(self, text)
self.sortable = sortable
def __lt__(self, other):
if getattr(self.parent(), 'sortable', True):
return QtGui.QStandardItem.__lt__(self, other)
return False
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Call setSortingEnabled(bool) on your QTreeView instance. Here is the corresponding docu for c++ and here is the link to pyqt api docu for this function