Can't loop through a column for QTableWidget - python

I need some assistance, because this problem simply doesn't make sense... Indentation is looking a bit off sorry for that...
self.myData = [["facebook-icon", "Facebook", str(self.mykeys[0][1]), "*" *len(self.passes[0])], ......
Only the first item in the table is getting populated, even though the rowCount prints out the number 3.. thats what is puzzling me.. would love someone trying out this code, I am a Python newbie
passAmount = len(self.myData)
print("There are %x items in myData" % (passAmount))
rowCount = self.tableWidget.rowCount()
print("There are %x items in the table" % (rowCount))
for row in range(0, rowCount):
cellText = self.tableWidget.itemAt(row,0).text()
if(cellText == "facebook-icon"):
self.tableWidget.itemAt(row, 0).setText("")
print(imagePaths[0])
fb = QPixmap(imagePaths[0]).scaledToWidth(20)
label = QLabel()
label.setPixmap(fb)
# label.setScaledContents(True)
self.tableWidget.setCellWidget(row, 0, label)
elif(cellText == "blogger-icon"):
...
self.tableWidget.setFont(self.font)
self.tableWidget.resizeColumnsToContents()
self.tableWidget.resizeRowsToContents()
self.tableWidget.doubleClicked.connect(self.on_table_click)
# Show widget
self.show()
Am I doing somethin wrong??

As I see you want to get elements from the first column, but itemAt() does not return the item given a row and column but to a geometric position, instead you should use the item() method. In addition we can reduce code using a dictionary:
dict_icons = {
"facebook-icon": imagePaths[0],
"blogger-icon": imagePaths[1]
}
for row in range(0, 3):
item = self.tableWidget.item(row, 0)
image_path = dict_icons.get(item.text())
if image_path is not None:
item.setText("")
pixmap = QPixmap(image_path).scaledToWidth(20)
label = QLabel(pixmap=pixmap)
self.tableWidget.setCellWidget(row, 0, label)

Related

How to move items from one QTreeWidget to another QTreeWidget and keep track of information?

I have a GUI where user selects gas components from list and moves it to 'Chosen' and another button takes text from 'Chosen' that has columns: Gas Component, Molecular Weight, Mol%. The first two columns get information from a dictionary that i've created, and last column is user input.
When button is clicked and all values are filled in 'Chosen', it will ask user for a number, n = 1-6 , it will then take rows with n highest mol% in 'Chosen' and create n rows in Results and add Gas Component text with n highest mol% values, to first column in 'Results'
I am currently using dictionaries to keep track of information.
def calculategas(self):
#makes sure dictionaries are clear for any errors on rerunning button
self.sortedmol.clear()
self.componentDic1.clear()
self.componentDic2.clear()
self.componentDic3.clear()
self.mmDict.clear()
self.mfDict.clear()
self.mDict.clear()
self.massFracDict.clear()
self.molarmassDict.clear()
self.item_.clear()
self.lookup.clear()
root = self.chosen.invisibleRootItem()
child_count = root.childCount()
for i in range(child_count):
item = root.child(i)
#Takes text from self.chosen QTreeWidget (Top-right)
component = item.text(0)
molWeight = item.text(1)
componentMol = float(item.text(2))
#creates dictionary of items in self.chosen
self.componentDic1[component] = componentMol
self.componentDic2[molWeight] = componentMol
#Sorts dictionaries above from highest to lowest
self.sortedmol = dict(sorted(self.componentDic1.items(), key=operator.itemgetter(1),
reverse=True)) # Sorted component list - largest to smallest mol%
self.sortedmolar = dict(sorted(self.componentDic2.items(), key=operator.itemgetter(1),
reverse=True)) # Sorted molar mass list - largest to smallest mol%
# change values of self.sortedmol with keys of self.sortedmolar
self.lookup = {v:k for k, v in self.sortedmol.items()}
self.componentDic3 = {self.lookup[v]: float(k) for k, v in self.sortedmolar.items()}
##Copies so original doesn't change
self.mmDict = self.sortedmol.copy()
self.mfDict = self.mmDict.copy()
self.mDict = self.componentDic3.copy()
###Calculations
self.molarmassDict = {k: round(v * self.mmDict[k] / 100, 3) for k, v in self.mDict.items() if
k in self.mmDict}
summolmDict = round(sum(self.molarmassDict.values()), 3)
self.massFracDict = {k: round(self.molarmassDict[k] / summolmDict, 3) for k, v in self.molarmassDict.items()
if
k in self.molarmassDict}
componentNum, ok = QInputDialog.getText(None, 'Number of components', 'How many components do you wish to use?')
if (ok):
#Remove any items in result QTreeWidget
current_item = self.result.invisibleRootItem()
children = []
for child in range(current_item.childCount()):
children.append(current_item.child(child))
for child in children:
current_item.removeChild(child)
#Adds rows to self.result QTreeWidget
for i in range(int(componentNum)):
self.item_[i] = QtWidgets.QTreeWidgetItem(self.result)
self.item_[i].setFlags(
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
if len(self.sortedmol) > int(componentNum): # takes only # of components user wants
##Adds the number of components user inputs with highest mol% to self.result
root = self.result.invisibleRootItem()
child_count = root.childCount()
for i in range(child_count):
item = root.child(i)
item.setText(0, str(list(self.massFracDict)[i])) # update first column with dictionary keys
else:
###This section will change
root = self.result.invisibleRootItem()
child_count = root.childCount()
for i in range(child_count):
item = root.child(i)
item.setText(0, str(list(self.massFracDict)[i])) # update first column with dictionary keys
Currently everything works except that when there is a duplicate value in mol% or molecular weight it will tend to skip it.
Dictionary self.sortedmol:
Keys = Gas Component text
Values = mol% text
Dictionary self.sortedmolar:
Keys = Molecular Weight text
Values = mol% text
Problems:
If two components have same molecular weight, it will ignore it
If two components have same mol%, it will ignore it
Overall goal: Add rows with n highest mol% in 'Chosen' to 'Result and keep values for later calculations.
Question: Is there any way to fix this error, or use another way to get same desired results?
Step1:
Step2:
If you want to get the n rows where the mol% are the highest then you must use a QSortFilterProxyModel to sort, and another to filter.
from PyQt5 import QtCore, QtGui, QtWidgets
ListRole = QtCore.Qt.UserRole
VisibleRole = QtCore.Qt.UserRole + 1
class TopProxyModel(QtCore.QSortFilterProxyModel):
#property
def number(self):
if not hasattr(self, "_number"):
self._number = -1
return self._number
#number.setter
def number(self, number):
self._number = number
self.invalidateFilter()
def filterAcceptsRow(self, sourceRow, sourceParent):
if self.number < 0:
ix = self.sourceModel().index(sourceRow, 2)
self.sourceModel().setData(ix, False, VisibleRole)
return True
return sourceRow < self.number
class BlankDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
if not index.data(VisibleRole):
option.text = ""
def setModelData(self, editor, model, index):
sm = model
ix = index
while hasattr(sm, "sourceModel"):
ix = sm.mapToSource(ix)
sm = sm.sourceModel()
sm.setData(ix, editor.value(), QtCore.Qt.DisplayRole)
if not sm.data(ix, VisibleRole):
sm.setData(ix, True, VisibleRole)
class ReadOnlyDelegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, option, index):
return None
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
datas = [
("IsonButane", 58.12, 13),
("IsonPentane", 75.12, 3),
("Methane", 16.04, 5),
("Nitrogen", 28.01, 5),
("Hexane", 86.17, 5),
("Hydrogen", 2.02, 13),
("Hydrogen Sulfide", 34.08, 2),
]
add_button = QtWidgets.QPushButton(">>>", clicked=self.add_row)
remove_button = QtWidgets.QPushButton("<<<", clicked=self.remove_row)
select_button = QtWidgets.QPushButton("Calculate", clicked=self.select)
sp = select_button.sizePolicy()
sp.setHorizontalPolicy(QtWidgets.QSizePolicy.Maximum)
select_button.setSizePolicy(sp)
self.listwidget = QtWidgets.QListWidget(
selectionMode=QtWidgets.QAbstractItemView.MultiSelection
)
for data in datas:
item = QtWidgets.QListWidgetItem(data[0])
item.setData(ListRole, data)
self.listwidget.addItem(item)
self.tree_widget = QtWidgets.QTreeWidget(
columnCount=3,
indentation=0,
selectionMode=QtWidgets.QAbstractItemView.MultiSelection,
)
for i, T in enumerate(
(ReadOnlyDelegate, ReadOnlyDelegate, BlankDelegate)
):
delegate = T(self.tree_widget)
self.tree_widget.setItemDelegateForColumn(2, delegate)
self.tree_widget.setHeaderLabels(
["Gas Component", "Molecular Weight", "Mol%"]
)
self.tree_view = QtWidgets.QTreeView(indentation=0)
proxy_sort = QtCore.QSortFilterProxyModel(self)
proxy_sort.setSourceModel(self.tree_widget.model())
proxy_sort.sort(2, QtCore.Qt.DescendingOrder)
self.proxy_top = TopProxyModel(self)
self.proxy_top.number = 0
self.proxy_top.setSourceModel(proxy_sort)
self.tree_view.setModel(self.proxy_top)
lay = QtWidgets.QGridLayout(self)
lay.addWidget(QtWidgets.QLabel("<b>Available Gases:</b>"), 0, 0)
lay.addWidget(self.listwidget)
vlay = QtWidgets.QVBoxLayout()
vlay.addStretch()
vlay.addWidget(add_button)
vlay.addWidget(remove_button)
vlay.addStretch()
lay.addLayout(vlay, 1, 1)
lay.addWidget(QtWidgets.QLabel("<b>Chosen Gases</b>"), 0, 2)
lay.addWidget(self.tree_widget, 1, 2)
lay.addWidget(select_button, 2, 2, alignment=QtCore.Qt.AlignCenter)
lay.addWidget(QtWidgets.QLabel("<b>Result:</b>"), 3, 2)
lay.addWidget(self.tree_view, 4, 2)
#QtCore.pyqtSlot()
def add_row(self):
for item in self.listwidget.selectedItems():
data = item.data(ListRole)
text = item.text()
if self.tree_widget.findItems(text, QtCore.Qt.MatchExactly):
continue
it = self.listwidget.takeItem(self.listwidget.row(item))
item = QtWidgets.QTreeWidgetItem()
self.tree_widget.addTopLevelItem(item)
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
for i, e in enumerate(data):
item.setData(i, QtCore.Qt.DisplayRole, e)
#QtCore.pyqtSlot()
def remove_row(self):
rows = [
self.tree_widget.indexOfTopLevelItem(item)
for item in self.tree_widget.selectedItems()
]
for row in sorted(rows, reverse=True):
item = self.tree_widget.takeTopLevelItem(row)
data = []
for i in range(self.tree_widget.columnCount()):
data.append(item.data(i, QtCore.Qt.DisplayRole))
it = QtWidgets.QListWidgetItem(data[0])
it.setData(ListRole, data)
self.listwidget.addItem(it)
if item is not None:
del item
#QtCore.pyqtSlot()
def select(self):
last_number = max(self.proxy_top.number, 0)
number, ok = QtWidgets.QInputDialog.getInt(
None,
"Number of components",
"How many components do you wish to use?",
last_number,
min=-1,
max=self.tree_widget.topLevelItemCount(),
)
if ok:
self.proxy_top.number = number
for i in range(self.tree_widget.topLevelItemCount()):
it = self.tree_widget.topLevelItem(i)
it.setData(2, VisibleRole, False)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

Fetching Value's From Columns Separately And Display Through Label - Python

How can I fetch values from each column of database separately and display each through label in python?
class display:
def __init__(self, master,ad):
self.master = master
self.master.title("STUDENT-INFO")
self.f = Frame(self.master,height = 1200, width = 1200)
self.f.propagate(0)
self.f.pack()
self.e1=ad.e1.get()
self.e2=ad.e2.get()
self.b1=Button(self.master,text="PRINT",width=15,command=self.print1)
self.b1.place(x=35,y=200)
self.exit = Button(self.f, text = 'EXIT', width = 15, command = self.exit_window)
self.exit.place(x=35,y=400)
def print1(self):
cursor.execute("select emp_name,pf,monthly_sal_inhand,bonus,yearly_sal_inhand from details6 where emp_id='{}' and password='{}'".format(self.e1,self.e2))
r=cursor.fetchall()
s=r[0]+""+r[1]+""+r[2]+""+r[3]
self.l3=Label(self.master,text='Format : Employee_name Monthly_pf Final_monthly_salary Yearly_Bonus Final_yearly_salary ',width=120)
self.l3.place(x=250,y=200)
self.l3=Label(self.master,text=s,width=80)
When I run this code I get an error message:
CONCATENATE ONLY TUPLE (NOT str) to tuple
You can in a better way print them in a list vertically by using the listWidget.
def print1(self):
list1 = []
cursor.execute("select emp_name,pf,monthly_sal_inhand,bonus,yearly_sal_inhand from
details6 where emp_id='{}' and password='{}'".format(self.e1,self.e2))
r=cursor.fetchall()
for i in range(len(r)):
list1.append(r[i][0])
#Now we have all the elements in list1 as a list
for in range(len(list1)):
item=list1[i]
self.listWidget.addItem(item)

Problems assigning a value from a randomly populated array to a tkinter button

Hello I am trying to create a game where you click on a button and it tells you if it is treasure or a bandit. It if is treasure then you get points if it is a bandit you loose your coins.
I have created the following code but cannot find a way of finding out if I have managed to set the buttons to the values stored in the array.
How do you use the data in the array and when a button is clicked it tells you what the value is.
Am I doing the array correctly any help would be appreciated I am going round in circles and cannot think straight now.
from tkinter import *
import tkinter.messagebox
import random
#count=0
root = Tk()
TreasureMap = Frame(root)
TreasureMap.grid()
root.title("TreasureMap")
text_box = Entry(TreasureMap, justify=RIGHT)
text_box.grid(row = 0, column = 0, columnspan = 8,)
text_box.insert(0, "0")
amount_to_add='B'
my_array = [[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0]]
my_array[random.randrange(len(my_array))].append(amount_to_add)
my_array[random.randrange(len(my_array))].append(amount_to_add)
my_array[random.randrange(len(my_array))].append(amount_to_add)
my_array[random.randrange(len(my_array))].append(amount_to_add)
Treasure='T'
my_array[random.randrange(len(my_array))].append(Treasure)
my_array[random.randrange(len(my_array))].append(Treasure)
my_array[random.randrange(len(my_array))].append(Treasure)
my_array[random.randrange(len(my_array))].append(Treasure)
my_array[random.randrange(len(my_array))].append(Treasure)
my_array[random.randrange(len(my_array))].append(Treasure)
my_array[random.randrange(len(my_array))].append(Treasure)
my_array[random.randrange(len(my_array))].append(Treasure)
my_array[random.randrange(len(my_array))].append(Treasure)
my_array[random.randrange(len(my_array))].append(Treasure)
print(my_array)
def changelabel(): `
tkinter.messagebox.showinfo('Hellow this button works') ``
print('hello this button works') ` ``
print(my_array) `` ``
return
i = 0
bttn = []
for j in range(1,9):`
for k in range(8): ``
bttn.append(Button(TreasureMap, text = ' ', value=random.shuffle
(my_array),command=changelabel))
bttn[i].grid(row = j, column = k)
i += 1 ``
TreasureMap.mainloop()
This may be what you're wanting to do.
Borrowing info from this answer, I put a callback in the Button command to pass the row and column numbers.
Also, 'B' and 'T' are being appended to each array of 0's, instead of getting assigned to locations within the array, which is what I think you want.
I made a few other changes, including fixing the for loops to start from 0 (the first row), etc.
# previous code
amount_to_add='B'
my_array = [[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0]]
# ... all code up to here unchanged ...
for _ in range(4):
my_array[random.randrange(len(my_array))][random.randrange(len(my_array))] = amount_to_add
Treasure='T'
for _ in range(4):
my_array[random.randrange(len(my_array))][random.randrange(len(my_array))] = Treasure
# print my_array # uncomment to check array values before shuffle
random.shuffle(my_array)
# print my_array # and after shuffle to confirm button is getting the correct values
def changelabel(j,k):
tkinter.messagebox.showinfo('Button %d,%d' % (j,k), 'Button %d,%d contains a %s' % (j,k, my_array[j][k]))
print('hello this button works')
# return # not needed
i = 0
bttn = []
for j in range(0,8):
for k in range(8):
bttn.append(Button(TreasureMap, text = ' ', command= lambda row = j, column = k: changelabel(row, column)))
bttn[i].grid(row = j, column = k)
i += 1
Feel free to comment or ask questions if this doesn't do what you were asking for. Otherwise, hope it helps.

Creating a custom item for QComboBox in Pyside

I want to create an item for my QComboBox that displays a string and 4 pixmaps in a row (the final usage is so that the user can pick from a list of colour schemes).
Can anyone help me customise the QStandardItem to get this effect? I thought I could use the rows to do to it but I've not had much luck. This is what I've tried so far...
myComboBox = QtGui.QComboBox()
item = QtGui.QStandardItem()
item.setRowCount(4)
colour1 = QtGui.QPixmap(16, 16)
colour1 .fill(QtGui.QColor("red"))
colour2 = QtGui.QPixmap(16, 16)
colour2 .fill(QtGui.QColor("blue"))
colour3 = QtGui.QPixmap(16, 16)
colour3 .fill(QtGui.QColor("white"))
childitem1 = QtGui.QStandardItem(QtGui.QIcon(colour1), "1")
childitem2 = QtGui.QStandardItem(QtGui.QIcon(colour2), "2")
childitem3 = QtGui.QStandardItem(QtGui.QIcon(colour3), "3")
item.setChild(0, childitem1)
item.setChild(1, childitem2)
item.setChild(2, childitem3)
myComboBox.model().appendRow(item)
But I just get an empty item and none of the children are visible - there's a good chance I've completely misunderstood how this works :)
You have to create a QStandarItemModel, append your items to it, and at the end you have to set this model to your combobox with myComboBox.setModel().
Something like this
itemModel = QStandardItemModel()
# create your items as you want
itemModel.appendRow(your_items)
myComboBox.setModel(itemModel)
I've managed to get a sort of half solution by putting a table view into the combo box like this:
itemModel = QtGui.QStandardItemModel()
item1 = QtGui.QStandardItem("1")
item2 = QtGui.QStandardItem("2")
item3 = QtGui.QStandardItem("3")
itemModel.appendRow([item1, item2, item3])
myComboBox.setModel(itemModel)
tv = QtGui.QTableView()
tv.setModel(itemModel)
tv.horizontalHeader().setVisible(False)
tv.verticalHeader().setVisible(False)
tv.resizeColumnsToContents()
tv.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
myComboBox.setView(tv)
It's a not 100% pretty but it just about does the job! Thanks for the help getting there.

Problems with wx.ListCtrl

Here is a snippet
self.list_ctrl = wx.ListCtrl(self, size=(-1,100),
style=wx.LC_ICON|wx.LC_ALIGN_LEFT
)
il = wx.ImageList(16,16,True)
png = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN,wx.ART_OTHER, (16,16))
il.Add(png)
self.list_ctrl.AssignImageList(il,wx.IMAGE_LIST_NORMAL)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
self.list_ctrl.InsertImageStringItem(0,"1",0)
self.list_ctrl.InsertImageStringItem(1,"2",0)
My problem is that the icons appear to the top of the text which should not happen because I put wx.LC_ALIGN_LEFT in the style. I would like the icons to appear left of the text.
Another problem is that, I want one element per row. In my code it is almost like one element per column.
Can anyone help me with any of these problems?
Thanks.
Looking at the wxPython demo for the ListCtrl, it looks like they use SetImageList() instead of AssignImageList(). Not sure what the difference is though. I don't see where you're inserting any text though. You'd need to use SetStringItem to put text in the other columns from what I can see.
EDIT: Code from wxPython Demo package, ListCtrl demo:
self.il = wx.ImageList(16, 16)
self.idx1 = self.il.Add(images.Smiles.GetBitmap())
self.sm_up = self.il.Add(images.SmallUpArrow.GetBitmap())
self.sm_dn = self.il.Add(images.SmallDnArrow.GetBitmap())
And then we add data / images to the widget
def PopulateList(self):
if 0:
# for normal, simple columns, you can add them like this:
self.list.InsertColumn(0, "Artist")
self.list.InsertColumn(1, "Title", wx.LIST_FORMAT_RIGHT)
self.list.InsertColumn(2, "Genre")
else:
# but since we want images on the column header we have to do it the hard way:
info = wx.ListItem()
info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
info.m_image = -1
info.m_format = 0
info.m_text = "Artist"
self.list.InsertColumnInfo(0, info)
info.m_format = wx.LIST_FORMAT_RIGHT
info.m_text = "Title"
self.list.InsertColumnInfo(1, info)
info.m_format = 0
info.m_text = "Genre"
self.list.InsertColumnInfo(2, info)
items = musicdata.items()
for key, data in items:
index = self.list.InsertImageStringItem(sys.maxint, data[0], self.idx1)
self.list.SetStringItem(index, 1, data[1])
self.list.SetStringItem(index, 2, data[2])
self.list.SetItemData(index, key)

Categories

Resources