I'm working with a listWidget in PyQT5. I would like to have a hidden value associated with each item in the list that I can extract when the list text is clicked.
class Gui(QtWidgets.QMainWindow, ui_tutorial.Ui_MainWindow):
def __init__(self):
super(self.__class__, self).__init__()
self.exiting = True
self.setupUi(self)
self.fill_list()
self.listWidget_emails.itemClicked.connect(self.extract)
def fill_list()
w = self.listWidget
w.clear()
titles = [['title_1', 1], ['title_2', 2], 'title_3', 3]]
for t in titles:
title = t[0]
value = t[1]
w.addItem(title, value) #this does not work
def extract(self, list_item):
w = self.listWidget
myValue = list_item.value() #This is just to describe what I want. Of course it doesn't work
def main():
app = QtWidgets.QApplication(sys.argv)
form = Gui()
form.show() # Show the form
app.exec_() # start the app
if __name__ == '__main__':
main()
You could construct a QListWidgetItem for each title and assign your own value property to the object.
def fill_list(self):
w = self.listWidget
w.clear()
titles = [['title_1', 1], ['title_2', 2], ['title_3', 3]]
for t in titles:
item = QtWidgets.QListWidgetItem(t[0])
item.value = t[1]
w.addItem(item)
def extract(self, list_item):
myValue = list_item.value
Related
Without clicking the search button everything works fine and returns a value.
However, using the search button will cause the code to pause.
The main issue is the Check() nested in chooseBoard() which calls in on itself causing a constant 'hidden loop'.
This means that the code doesn't carry on from:
board = tempPreset.chooseBoard(None)
and unable to return wanted value.
In short, my question is how do I fix the nested loop issue of not carrying on after the check() is completed when the search button is pressed. As the value is correct when I print it from there.
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
class PresetUpdate:
def __init__(self,master,area,board):
self.root = master
self.root.title('Preset')
self.root.geometry(area)
self.board = board
def boardId(self,name):
self.name = name
self.var.set(name)
self.root.destroy()
def chooseBoard(self, newBoard):
def check():
#set variables
self.newBoard = {}
r = re.compile(self.e.get(), re.IGNORECASE)
#regex to see words in list
for k in self.board:
if r.search(k) != None:
self.newBoard.update({r.search(k).string : self.board[r.search(k).string]})
if self.newBoard == {}:
self.newBoard = self.board
self.root.destroy()
#creating new root
master = tk.Tk()
self.__init__(master,'460x475',self.board)
#re-calling function with update list
self.chooseBoard(self.newBoard)
return self.board[self.name]
#print(self.board[self.name])
#set variables
self.newBoard = self.board if newBoard is None else newBoard
self.var = tk.StringVar()
self.button = {}
#setting search bar / button
self.e = tk.Entry(self.root,width=30)
self.e.grid(row=0,column=2,padx=10,pady=10)
click = tk.Button(self.root, text='Search', height=1,width=5,command=check)
click.grid(row=0,column=1,padx=10,pady=10)
#creating buttons of dct
for i,boardName in enumerate(self.newBoard):
#print(i,boardName,self.board[boardName])
self.button[i] = tk.Button(self.root, text=boardName,height=2,width=30,command=lambda name=boardName:self.boardId(name))
self.button[i].grid(row=i+1,column=1,padx=10,pady=10)
#pause until a button has been pressed
self.button[i].wait_variable(self.var)
return self.board[self.name]
r = {'test1' : '0','test2' : '1','test3' : '2','test4' : '3','test5' : '4'}
def main():
if __name__ == '__main__':
master = tk.Tk()
tempPreset = PresetUpdate(master,'460x475',r)
board = tempPreset.chooseBoard(None)
print(board)
master.mainloop()
main()
I found the solution:
def chooseBoard(self, board):
def check():
#set variables
self.newBoard = {}
r = re.compile(self.e.get(), re.IGNORECASE)
#regex to see words in list
for k in self.board:
if r.search(k) != None:
self.newBoard.update({r.search(k).string : self.board[r.search(k).string]})
if self.newBoard == {}:
self.newBoard = self.board
for i,item in enumerate(self.board):
if item not in self.newBoard:
self.button[i].destroy()
if self.newBoard == self.board:
for i,item in enumerate(self.board):
self.button[i].destroy()
createButtons()
#set variables
self.newBoard = self.board if self.newBoard is None else self.newBoard
self.var = tk.StringVar()
self.button = {}
#setting search bar / button
self.e = tk.Entry(self.root,width=30)
self.e.grid(row=0,column=2,padx=10,pady=10)
click = tk.Button(self.root, text='Search', height=1,width=5,command=check)
click.grid(row=0,column=1,padx=10,pady=10)
#creating buttons of dct
def createButtons():
for i,boardName in enumerate(self.newBoard):
#print(i,boardName,self.board[boardName])
self.button[i] = tk.Button(self.root, text=boardName,height=2,width=30,command=lambda name=boardName:self.boardId(name))
self.button[i].grid(row=i+1,column=1,padx=10,pady=10)
return i
i = createButtons()
#check()
#pause until a button has been pressed
self.button[i].wait_variable(self.var)
return self.board[self.name]
This question already has an answer here:
pyqt QTableWidgetItem connect signal
(1 answer)
Closed 3 years ago.
I am trying to retrieve the editted data from a pyqt5 qtablewidget and am struggling to understand how to do this. My simple code is shown below:
class Delegate(QStyledItemDelegate):
def createEditor(self, parent, option, index):
DBL_MAX = 1.7976931348623157e308
editor = QDoubleSpinBox(parent, minimum=-DBL_MAX, maximum=DBL_MAX, decimals=323)
return editor
class TableView(QTableWidget):
def __init__(self, z, *args):
super(TableView, self).__init__(*args)
self.z = z
self.setz()
self.resizeColumnsToContents()
self.resizeRowsToContents()
delegate = Delegate(self)
self.setItemDelegate(delegate)
def setz(self):
horHeaders = []
for j, (key, values) in enumerate(sorted(self.z.items())):
horHeaders.append(key)
for i, value in enumerate(values):
newitem = QTableWidgetItem()
newitem.setData(Qt.EditRole, value)
self.setItem(i, j, newitem)
self.setHorizontalHeaderLabels(horHeaders)
def slot(self):
row= self.tableWidget.currentItem()
print(str(row))
def main(args):
z = {
"Let's Sum This Row 1": [0, 0],
"Let's Sum This Row 2": [0, 0],
}
app = QApplication(args)
table = TableView(z, 2, 2)
table.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main(sys.argv)
a = z
sum1=a[0][0]+a[0][1]
sum2=a[1][0]+a[1][1]
print(sum1)
print(sum2)
In my simple example my initial z data is a zeros. Let's say that the user changes the first rows to 1's and the second row to 2's.
The end output I want is sum1 = 2 and sum2 = 4.
How do i tell my program to read the end user editted matrix and store that back to a variable so that I can do more work further on in my program?
From my research, it looks like itemchanged may do the trick, but I am struggling to understand how to implement this in my code.
edited your code to add itemChanged and calculate
from PyQt5.QtWidgets import (QStyledItemDelegate, QDoubleSpinBox, QTableWidget, QTableWidgetItem, QApplication)
from PyQt5.QtCore import (Qt, QSize)
import sys
class Delegate(QStyledItemDelegate):
def createEditor(self, parent, option, index):
DBL_MAX = 1.7976931348623157e308
editor = QDoubleSpinBox(parent, minimum=-DBL_MAX, maximum=DBL_MAX, decimals=323)
return editor
class TableView(QTableWidget):
def __init__(self, z, *args):
super(TableView, self).__init__(*args)
self.setMinimumSize(QSize(800, 600))
self.z = z
self.setz()
self.resizeColumnsToContents()
self.resizeRowsToContents()
delegate = Delegate(self)
self.setItemDelegate(delegate)
def setz(self):
horHeaders = []
for j, (key, values) in enumerate(sorted(self.z.items())):
horHeaders.append(key)
for i, value in enumerate(values):
newitem = QTableWidgetItem()
newitem.setData(Qt.EditRole, value)
newitem
self.setItem(i, j, newitem)
self.setHorizontalHeaderLabels(horHeaders)
def slot(self):
row = self.tableWidget.currentItem()
print(str(row))
def main(args):
z = {
"Let's Sum This Row 1": [0, 0],
"Let's Sum This Row 2": [0, 0],
}
app = QApplication(args)
table = TableView(z, 2, 2)
def _calculate():
for j in range(table.columnCount()):
counter = 0
for i in range(table.rowCount()):
counter = counter + int(table.item(i, j).data(0))
print(f"col{j}: sum={counter}")
table.itemChanged.connect(_calculate)
table.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main(sys.argv)
I have set up a treeview to display data from my sqlite db. I am able to fill the first column with a query and now I need to fill the other columns with different queries.
# Top Container
top_frame = ttk.Frame()
top_frame.grid(column=0, row=0)
# create a treeview with dual scrollbars
list_header = ['First', 'Second', 'Third']
self.tree = ttk.Treeview(columns=list_header, show="headings")
vsb = ttk.Scrollbar(orient="vertical",
command=self.tree.yview)
hsb = ttk.Scrollbar(orient="horizontal",
command=self.tree.xview)
self.tree.configure(yscrollcommand=vsb.set,
xscrollcommand=hsb.set)
self.tree.grid(column=0, row=0, sticky=(N, S, E, W), in_=top_frame)
vsb.grid(column=1, row=0, sticky=(N, S), in_=top_frame)
hsb.grid(column=0, row=1, sticky=(E, W), in_=top_frame)
# Display the headers
for col in list_header:
self.tree.heading(col, text=col.title(), command=lambda c=col: sortby(self.tree, c, 0))
# adjust the column's width to the header string
self.tree.column(col)
# Display the data
query = ProjectNumber.select()
for item in query:
self.tree.insert('', 'end', values=item.project_num)
how can i access the next column and fill it with a separate query?
if I've understand, below you can see a working example of what you want to do.
The example is write in oo approach.
After launch the script click on Load button, you will see the treeview populate with
data that simulate a recordset ,list of a tuple. After try to click on a item of the
treeview and see what happens. I've add even click and double click event callback.
The data represent Italian pasta dishes.
import tkinter as tk
from tkinter import ttk
class App(tk.Frame):
def __init__(self,):
super().__init__()
self.master.title("Hello World")
self.init_ui()
def init_ui(self):
f = tk.Frame()
tk.Label(f, text = "Buon Appetito").pack()
cols = (["#0",'','w',False,200,200],
["#1",'','w',True,0,0],)
self.Pasta = self.get_tree(f, cols, show="tree")
self.Pasta.show="tree"
self.Pasta.pack(fill=tk.BOTH, padx=2, pady=2)
self.Pasta.bind("<<TreeviewSelect>>", self.on_selected)
self.Pasta.bind("<Double-1>", self.on_double_click)
w = tk.Frame()
tk.Button(w, text="Load", command=self.set_values).pack()
tk.Button(w, text="Close", command=self.on_close).pack()
w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=0)
f.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)
def set_values(self,):
#.insert(parent, index, iid=None, **kw)
rs = [(0,'Spaghetti'),(1,'Rigatoni'),(2,'Pennette')]
for i in rs:
#print(i)
pasta = self.Pasta.insert("", i[0], text=i[1], values=(i[0],'pasta'))
rs_dishes = self.load_dishes(i[0])
if rs_dishes is not None:
for dish in rs_dishes:
#print(dish)
wards = self.Pasta.insert(pasta, dish[0],text=dish[1], values=(dish[0],'dishes'))
def load_dishes(self, i):
rs = [(0,'Spaghetti aglio e olio'),
(1,'Rigatoni alla matriciana'),
(1,'Rigatoni al pesto'),
(1,'Rigatoni alla norma'),
(2,'Pennette al pesto'),
(2,'Pennette alla wodka'),
(2,'Pennette al tartufo'),
(0,'Spaghetti allo scoglio'),
(0,'Spaghetti al pesto'),
(0,'Spaghetti alla carbonara'),
(0,'Spaghetti alla puttanesca')]
r = [x for x in rs if x[0] == i]
return r
def on_selected(self, evt=None):
selected_item = self.Pasta.focus()
d = self.Pasta.item(selected_item)
if d['values']:
if d['values'][1]=='dishes':
pk = d['values'][0]
print("pk: {}".format(pk))
def on_double_click(self, evt=None):
if self.Pasta.focus():
item_iid = self.Pasta.selection()
pk = self.Pasta.item(self.Pasta.focus())['text']
print(item_iid, pk)
def get_tree(self,container, cols, size=None, show=None):
headers = []
for col in cols:
headers.append(col[1])
del headers[0]
if show is not None:
w = ttk.Treeview(container,show=show)
else:
w = ttk.Treeview(container,)
w['columns']=headers
for col in cols:
w.heading(col[0], text=col[1], anchor=col[2],)
w.column(col[0], anchor=col[2], stretch=col[3],minwidth=col[4], width=col[5])
sb = ttk.Scrollbar(container)
sb.configure(command=w.yview)
w.configure(yscrollcommand=sb.set)
w.pack(side=tk.LEFT, fill=tk.BOTH, expand =1)
sb.pack(fill=tk.Y, expand=1)
return w
def on_close(self):
self.master.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()
i am trying to copy the text I enter into the text edit and store it into a string variable.
I have written the following code but it shows 'python has stopped working'
from PyQt5 import QtGui,QtWidgets,QtCore
import sys
class GUI(QtWidgets.QWidget):
def __init__(self):
super(GUI,self).__init__()
self.initUI()
def initUI(self):
review = QtWidgets.QLabel('Review')
reviewEdit = QtWidgets.QTextEdit()
grid = QtWidgets.QGridLayout()
grid.addWidget(review, 3, 0)
grid.addWidget(reviewEdit, 3, 1, 5, 1)
self.setLayout(grid)
self.setGeometry(300,300,350,300)
self.setWindowTitle('Sentiment Analysis')
button = QtWidgets.QPushButton("OK")
grid.addWidget(button)
button.clicked.connect(self.copyText)
self.show()
def copyText(self):
reviewEdit.setText("text")
print(text)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
GUI = GUI()
sys.exit(app.exec_())
The program stops working because of a NameError in the copyText() method. The reviewEdit variable doesn't exit in that scope, so you can't reference it.
The way to fix this is to make all the child widgets attributes of the main class - then you can access them later using self:
class GUI(QtWidgets.QWidget):
def __init__(self):
super(GUI,self).__init__()
self.initUI()
def initUI(self):
self.review = QtWidgets.QLabel('Review')
self.reviewEdit = QtWidgets.QTextEdit()
grid = QtWidgets.QGridLayout()
grid.addWidget(self.review, 3, 0)
grid.addWidget(self.reviewEdit, 3, 1, 5, 1)
self.setLayout(grid)
self.setGeometry(300,300,350,300)
self.setWindowTitle('Sentiment Analysis')
self.button = QtWidgets.QPushButton("OK")
grid.addWidget(self.button)
self.button.clicked.connect(self.copyText)
self.show()
def copyText(self):
# self.reviewEdit.setText("text")
text = self.reviewEdit.toPlainText()
print(text)
First, you should make reviewEdit a member of GUI class. Like this:
self.reviewEdit = QtGui.QTextEdit()
next, in addBold(self), you get the text like this:
text = str(self.reviewEdit.toPlainText())
I have below code snippet from the help of stackoverflow followers.
I am able to filter the table now. but when i try to filter it sorts first as i enabled sort for the view.
I want to create the QTableview such a way that if i click on header it should sort. and should have a dropdown box (may be combox box style) at the right of every header. i am uploading a snap of how i want (which i made it in .NET)
Code Snippet
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtCore, QtGui
class myWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(myWindow, self).__init__(parent)
self.centralwidget = QtGui.QWidget(self)
self.view = QtGui.QTableView(self.centralwidget)
self.view.setSortingEnabled(True)
self.gridLayout = QtGui.QGridLayout(self.centralwidget)
self.gridLayout.addWidget(self.view, 1, 0, 1, 3)
self.setCentralWidget(self.centralwidget)
self.model = QtGui.QStandardItemModel(self)
for rowName in range(3) * 5:
self.model.invisibleRootItem().appendRow(
[ QtGui.QStandardItem("row {0} col {1}".format(rowName, column))
for column in range(3)
]
)
self.proxy = QtGui.QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.model)
self.view.setModel(self.proxy)
self.horizontalHeader = self.view.horizontalHeader()
self.horizontalHeader.sectionClicked.connect(self.horizontalHeader_Clicked)
#QtCore.pyqtSlot(int)
def horizontalHeader_Clicked(self, logicalIndex):
self.logicalIndex = logicalIndex
# local variable, and no parent
menuValues = QtGui.QMenu()
# delete the previous one
try:
self.signalMapper.deleteLater()
except:
pass
self.signalMapper = QtCore.QSignalMapper(self)
valuesUnique = [
self.proxy.index(row, self.logicalIndex).data().toString()
for row in xrange(self.proxy.rowCount())
]
print 'printing col %d values' % self.logicalIndex
for row in range(self.proxy.rowCount()):
print 'row %d Item %s' % (row,self.model.item(row, self.logicalIndex).text())
actionAll = QtGui.QAction("All", self)
actionAll.triggered.connect(self.actionAll)
menuValues.addAction(actionAll)
menuValues.addSeparator()
for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))):
action = QtGui.QAction(actionName, self)
self.signalMapper.setMapping(action, actionNumber)
action.triggered.connect(self.signalMapper.map)
menuValues.addAction(action)
self.signalMapper.mapped.connect(self.signalMapper_mapped)
headerPos = self.view.mapToGlobal(self.horizontalHeader.pos())
posY = headerPos.y() + self.horizontalHeader.height()
posX = headerPos.x() + self.horizontalHeader.sectionPosition(self.logicalIndex)
menuValues.exec_(QtCore.QPoint(posX, posY))
#QtCore.pyqtSlot()
def actionAll(self):
filterColumn = self.logicalIndex
filterString = QtCore.QRegExp( "",
QtCore.Qt.CaseInsensitive,
QtCore.QRegExp.RegExp
)
self.proxy.setFilterRegExp(filterString)
self.proxy.setFilterKeyColumn(filterColumn)
#QtCore.pyqtSlot(int)
def signalMapper_mapped(self, i):
stringAction = self.signalMapper.mapping(i).text()
filterColumn = self.logicalIndex
filterString = QtCore.QRegExp( stringAction,
QtCore.Qt.CaseSensitive,
QtCore.QRegExp.FixedString
)
self.proxy.setFilterRegExp(filterString)
self.proxy.setFilterKeyColumn(filterColumn)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
main = myWindow()
main.show()
main.resize(400, 600)
sys.exit(app.exec_())
This i how i am trying to get (Sort and filter)
If possible I need the ability to set the filter for selected columns only like in above image.
There is a discussion location here about the same topic: Quick way for QWidget in QHeaderView's columns?
They suggest that you would need to ditch the stock QHeaderView in your view, and provide your own custom widget for the header functionality, in order to place custom widgets into the header sections.