pyqt5 comboBox - get the associate value for selected item - python

i want to set a comboBox and show my table's column1 data as items and associated value column2 is for selected item id and want to setText in a qLabel.
i am using a model to view the items in comboBox and working fine. i can get the currentText value but how to get the associated value for the items.
in my case :
my sql table like:
type id
------------
DIV 2
TRANS 33
FEE 41
EXP 89
now , i can set the column1(type) values into comboBox successfully. now, if user selected value 'FEE' , than qlable should be updated as its associate id : 41. how to do that!
df=loadData()
model=PandasModel(df)
self.comboBox.setModel(model)
self.comboBox.setModelColumn(0)
content=self.comboBox.currentText()
self.label.setText(content) # content should be ID instead of currentText
pandasMode:
class PandasModel(QtCore.QAbstractTableModel):
def __init__(self, df = pd.DataFrame(), parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._df = df
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation == QtCore.Qt.Horizontal:
try:
return self._df.columns.tolist()[section]
except (IndexError, ):
return QtCore.QVariant()
elif orientation == QtCore.Qt.Vertical:
try:
return self._df.index.tolist()[section]+1
except (IndexError, ):
return QtCore.QVariant()
def data(self, index, role=QtCore.Qt.DisplayRole):
if index.isValid():
if role == QtCore.Qt.DisplayRole:
return str(self._df.iloc[index.row(), index.column()])
return None
def setData(self, index, value, role):
if not index.isValid():
return False
if role != QtCore.Qt.EditRole:
return False
row = index.row()
if row < 0 or row >= len(self._df.values):
return False
column = index.column()
if column < 0 or column >= self._df.columns.size:
return False
self._df.values[row][column] = value
self.dataChanged.emit(index, index)
return True
# def rowCount(self, parent=QtCore.QModelIndex()):
# return len(self._df.index)
def rowCount(self, parent=None):
return len(self._df.index)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self._df.columns)
def sort(self, column, order):
colname = self._df.columns.tolist()[column]
self.layoutAboutToBeChanged.emit()
self._df.sort_values(colname, ascending= order == QtCore.Qt.AscendingOrder, inplace=True)
self._df.reset_index(inplace=True, drop=True)
self.layoutChanged.emit()

Assuming that the model stores the id in the second column then it has to obtain the associated index:
ID_COLUMN = 1
index = self.comboBox.model().index(
self.comboBox.currentIndex(), ID_COLUMN, self.comboBox.rootModelIndex()
)
id_ = index.data()
print(id_)
self.label.setText(id_)

Related

removeRow in QTableView/QAbstractTableModel by CheckBox

I've created a table view where I'm trying to drop rows by clicking the checkbox embedded in the table view. I get to the point where it indexes the correct row when the checkbox is deselected, but the model refuse to remove the row and instead returns 'False'. Any thoughts? Still new to tableviews after switching from tablewidgets
class pandasModel(QAbstractTableModel):
def __init__(self, data, check_col=[0, 0]):
QAbstractTableModel.__init__(self)
self._data = data
self._check = check_col
cs = 0
if check_col[1]: cs = 2
self._checked = [[cs for i in range(self.columnCount())] for j in range(self.rowCount())]
def rowCount(self, parent=QModelIndex):
return self._data.shape[0]
def columnCount(self, parent=QModelIndex):
return self._data.shape[1]
def data(self, index, role):
if index.isValid():
data = self._data.iloc[index.row(), index.column()]
if role == Qt.DisplayRole:
if isinstance(data, float):
return f'{data:,.2f}'
elif isinstance(data, (int, np.int64)):
return f'{data:,}'
else:
return str(data)
elif role == Qt.TextAlignmentRole:
if isinstance(data, (float, int, np.int64)):
return Qt.AlignVCenter + Qt.AlignRight
elif role == Qt.CheckStateRole:
if self._check[0] > 0:
if self._check[0] == index.column():
return self._checked[index.row()][index.column()]
return None
def flags(self, index):
if not index.isValid(): return
return Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsEditable
def setData(self, index, value, role):
if not index.isValid() or role != Qt.CheckStateRole: return False
self._checked[index.row()][index.column()] = value
if value == 0:
print('checked')
self.removeRow(index.row()) #THIS IS WHERE IT RETURNS FALSE
self.dataChanged.emit(index, index)
return True
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self._data.columns[col]
return None

QTableView unexpectedly shifts left after inserting row to data using pandas

----How The Problem Looks Like----
after I clicked on the Record button, it becomes this
As you can see, the table just shifted to the left, hiding the vertical headers.
----Related Codes----
My tableivew is called tableViewTransaction, it uses a model to link to data in pandas' dataframe format. Here is how I connected them together inside the __init__ function of a QMainWindow.
self.data = pd.read_csv('transactions.txt', sep='\t', header=None)
self.data.columns = ["Name", "Price", "Action"]
self.model = PandasModel(self.data)
self.tableViewTransaction.setModel(self.model)
Here is my Model for the TableView
class PandasModel(QtCore.QAbstractTableModel):
def __init__(self, df = pd.DataFrame(), parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._df = df
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation == QtCore.Qt.Horizontal:
try:
return self._df.columns.tolist()[section]
except (IndexError, ):
return QtCore.QVariant()
elif orientation == QtCore.Qt.Vertical:
try:
# return self.df.index.tolist()
return self._df.index.tolist()[section]
except (IndexError, ):
return QtCore.QVariant()
def data(self, index, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if not index.isValid():
return QtCore.QVariant()
return QtCore.QVariant(str(self._df.ix[index.row(), index.column()]))
def setData(self, index, value, role):
row = self._df.index[index.row()]
col = self._df.columns[index.column()]
if hasattr(value, 'toPyObject'):
# PyQt4 gets a QVariant
value = value.toPyObject()
else:
# PySide gets an unicode
dtype = self._df[col].dtype
if dtype != object:
value = None if value == '' else dtype.type(value)
self._df.set_value(row, col, value)
return True
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self._df.index)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self._df.columns)
def sort(self, column, order):
colname = self._df.columns.tolist()[column]
self.layoutChanged.emit()
self._df.sort_values(colname, ascending= order == QtCore.Qt.AscendingOrder, inplace=True)
self._df.reset_index(inplace=True, drop=True)
self.layoutChanged.emit()
When the Record button is pressed, the following function is called:
def recordTransaction(self):
name = self.comboBoxStock.currentText()
price = self.lineEditMoney.text()
action = self.comboBoxAction.currentText()
self.data.loc[len(self.data.index)] = [name, price, action]
self.tableViewTransaction.model().layoutChanged.emit()
I know that name, price, action here is storing the correct information i.e. "stock1", "2", "Buy" in my above example.
----Full Code----
https://drive.google.com/file/d/1rU66yLqlQu0bTdINkSWxJe2E_OdMtS0i/view?usp=sharing
How to use:
first unzip it, then use python3 to run StockSim.py.
On a mac, just run python3 StockSim.py when you have went to the Stock Sim directory using terminal. Make sure you have python3 and pyqt5 installed first.
----------------------
All I want is that the TableView not shift to the left, any of your help would be very much appreciated!

Find index of value in Qlistview

I'am using PySide2 and want to search a QListView for a value and have that row selected. Like you can with .findText(string_to_search_for) on a QComboBox.
How can i search for a value in a Qlistview and have the index returned?
some additional info:
The model of my QListView is implementation of QAbstractTableModel i've written.
The model is filled with data from a database, in the first column the id and 2nd column the name of the Database item. The QListView is only showing the 2nd column. This is my code for the QTableModel.
from PySide2 import QtGui,QtCore
class TwoColumnTableModel(QtCore.QAbstractTableModel):
def __init__(self, row_data=[], column_data=[], parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.row_data = row_data
self.column_data = column_data
def rowCount(self, parent):
return len(self.row_data)
def columnCount(self, parent):
return len(self.column_data)
def flags(self, index):
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
row = index.row()
column = index.column()
value = self.row_data[row][column]
self.dataChanged.emit(row, column, [])
return value
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if section < len(self.column_data):
return self.column_data[section]
else:
return "TEMP COL"
def insertRows(self, position, rows, data=[], parent=QtCore.QModelIndex()):
self.beginInsertRows(parent, position, position + rows - 1)
for i in range(len(data)):
columns = []
row_column1 = data[i][0]
row_column2 = data[i][1]
columns.insert(0, row_column1)
columns.insert(1, row_column2)
self.row_data.insert(position, columns)
self.endInsertRows()
return True
def removeRows(self, position, rows, parent=QtCore.QModelIndex()):
self.beginRemoveRows()
for i in range(rows):
value = self.row_data[position]
self.row_data.remove(value)
self.endRemoveRows()
return True
I ended up creating the following function in QTableModel class:
def find_index_of_value(self, search_string, search_column):
for index in range(self.rowCount(None)):
model_index = self.index(index, 1)
index_value = self.data(model_index, search_column)
if index_value == search_string:
return model_index
The "search_string" being the string i'm looking for and the "search_column" being the column of the model where i want to search for that string. With the return index i can use the setCurrentIndex(index) on my QListView and that's it.

How can I check if the value passed in a PyQt TableModelView is an integer and not for example a letter/symbol?

I'm relatively new to Python and especially PyQt and model-view programming. I want to have it so that someone can only enter integers in my table and not letters/symbols etc. Here's the model I've made so far for my tableView widget:
class PixelTableModel(QtCore.QAbstractTableModel):
def __init__(self):
super(PixelTableModel, self).__init__()
self.pixel_coordinate = [[None, None, None, None]]
def rowCount(self, parent):
return 1
def columnCount(self, parent):
return 4
def flags(self, index):
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def setData(self, index, value, role = QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
self.pixel_coordinate[row][column] = value
print(self.pixel_coordinate) #testing
return True
return False
def data(self, index, role):
if role == QtCore.Qt.DisplayRole:
row = index.row()
column = index.column()
value = self.pixel_coordinate[row][column]
return value
def headerData(self, section, orientation, role): # section = row column, orientation = vertical/horizontal
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
dict = {0: "Xstart", 1: "Ystart", 2: "Xmax", 3: "Ymax"}
for key in dict:
if section == key:
return dict[key]
else:
return "Pixel coordinate"
It seems to work except obviously for the part where it still can take letters/symbols as input in the tableView. I've tried a couple of things in the setData() method but can't seem to get it work, always get some type of error or it won't even change the box at all. Thanks to anyone that can help me with this. Also sorry for bad English.
For anyone still interested, after going through it again fixed it with simple try except block:
def setData(self, index, value, role = QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
try:
row = index.row()
column = index.column()
string_to_int = int(value)
self.pixel_coordinate[row][column] = value
print(self.pixel_coordinate) #testing
return True
except ValueError:
print("Not a number")
return False
return False

PyQt4 QAbstractItemModel cuts of floats at 2 decimal places

I have an abstract item model. which is displayed as a tree.
The purpose is to store a set of preferences.
The code for the qt object is:
class QPreferenceModel(QAbstractItemModel):
'Convention states only items with column index 0 can have children'
#report_thread_error
def __init__(self, pref_struct, parent=None):
super(QPreferenceModel, self).__init__(parent)
self.rootPref = pref_struct
#report_thread_error
def index2Pref(self, index=QModelIndex()):
'''Internal helper method'''
if index.isValid():
item = index.internalPointer()
if item:
return item
return self.rootPref
#-----------
# Overloaded ItemModel Read Functions
#report_thread_error
def rowCount(self, parent=QModelIndex()):
parentPref = self.index2Pref(parent)
return parentPref.qt_row_count()
#report_thread_error
def columnCount(self, parent=QModelIndex()):
parentPref = self.index2Pref(parent)
return parentPref.qt_col_count()
#report_thread_error
def data(self, index, role=Qt.DisplayRule):
'''Returns the data stored under the given role
for the item referred to by the index.'''
if not index.isValid():
return QVariant()
if role != Qt.DisplayRole and role != Qt.EditRole:
return QVariant()
nodePref = self.index2Pref(index)
data = nodePref.qt_get_data(index.column())
var = QVariant(data)
print('---')
print('data = %r' % data)
print('type(data) = %r' % type(data))
#if isinstance(data, float):
#var = var.toDouble()[0]
print('var= %r' % var)
return var
#report_thread_error
def index(self, row, col, parent=QModelIndex()):
'''Returns the index of the item in the model specified
by the given row, column and parent index.'''
if parent.isValid() and parent.column() != 0:
return QModelIndex()
parentPref = self.index2Pref(parent)
childPref = parentPref.qt_get_child(row)
if childPref:
return self.createIndex(row, col, childPref)
else:
return QModelIndex()
#report_thread_error
def parent(self, index=None):
'''Returns the parent of the model item with the given index.
If the item has no parent, an invalid QModelIndex is returned.'''
if index is None: # Overload with QObject.parent()
return QObject.parent(self)
if not index.isValid():
return QModelIndex()
nodePref = self.index2Pref(index)
parentPref = nodePref.qt_get_parent()
if parentPref == self.rootPref:
return QModelIndex()
return self.createIndex(parentPref.qt_parents_index_of_me(), 0, parentPref)
#-----------
# Overloaded ItemModel Write Functions
#report_thread_error
def flags(self, index):
'Returns the item flags for the given index.'
if index.column() == 0:
# The First Column is just a label and unchangable
return Qt.ItemIsEnabled | Qt.ItemIsSelectable
if not index.isValid():
return Qt.ItemFlag(0)
childPref = self.index2Pref(index)
if childPref:
if childPref.qt_is_editable():
return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
return Qt.ItemFlag(0)
#report_thread_error
def setData(self, index, data, role=Qt.EditRole):
'Sets the role data for the item at index to value.'
if role != Qt.EditRole:
return False
leafPref = self.index2Pref(index)
result = leafPref.qt_set_leaf_data(data)
if result is True:
self.dataChanged.emit(index, index)
return result
#report_thread_error
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
if section == 0:
return QVariant('Config Key')
if section == 1:
return QVariant('Config Value')
return QVariant()
I assume the problem is probably in setData or data
def data(self, index, role=Qt.DisplayRule):
'''Returns the data stored under the given role
for the item referred to by the index.'''
if not index.isValid():
return QVariant()
if role != Qt.DisplayRole and role != Qt.EditRole:
return QVariant()
nodePref = self.index2Pref(index)
data = nodePref.qt_get_data(index.column())
var = QVariant(data)
print('---')
print('data = %r' % data)
print('type(data) = %r' % type(data))
#if isinstance(data, float):
#var = var.toDouble()[0]
print('var= %r' % var)
return var
def setData(self, index, data, role=Qt.EditRole):
'Sets the role data for the item at index to value.'
if role != Qt.EditRole:
return False
leafPref = self.index2Pref(index)
result = leafPref.qt_set_leaf_data(data)
if result is True:
self.dataChanged.emit(index, index)
return result
I was messing around with data to see if turning the QVariant into a double would do something. I also tried replacing Qt.DisplayRole and Qt.EditRole with Qt.UserRole.
I'm not actually sure what is controlling the display and edit precision of the float. The type is correct, but whenever I want to enter something like .0002 Qt prevents me from typing after .00
You could use a custom item delegate to adjust the precision of floats, but it might be overkill for this particular use-case.
A simpler solution would be to just return the values as strings - then you can format the displayed values in whatever way you like.

Categories