How can I change the text displayed in the second column of the rows selected in the treeview when the user hits 'Edit' in the UI? I'm using python and pyside but I'm not clear on how to do this.
What I want to happen is: When user clicks Edit in the UI i would like it to change the text of the selected Treeview Rows second columns. You can just change the text to say 'Hello' or something simple.
import sys
from PySide import QtGui, QtCore
class SortModel(QtGui.QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(SortModel, self).__init__(*args, **kwargs)
def lessThan(self, left, right):
leftData = self.sourceModel().data(left)
rightData = self.sourceModel().data(right)
if leftData:
leftData = leftData.lower()
if rightData:
rightData = rightData.lower()
print('L:', leftData, 'R:', rightData)
return leftData < rightData
class Browser(QtGui.QDialog):
def __init__(self, parent=None):
super(Browser, self).__init__(parent)
self.initUI()
def initUI(self):
self.resize(200, 300)
self.setWindowTitle('Assets')
self.setModal(True)
self.results = ""
self.uiItems = QtGui.QTreeView()
self.uiItems.setAlternatingRowColors(True)
self.uiItems.setSortingEnabled(True)
self.uiItems.sortByColumn(0, QtCore.Qt.AscendingOrder)
self.uiItems.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.uiItems.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
self.uiItems.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.uiItems.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self._model = self.create_model(self)
self._spmodel = SortModel(self)
self._spmodel.setSourceModel(self._model)
self._spmodel.setDynamicSortFilter(False)
self.uiItems.setModel(self._spmodel)
self.uiEdit = QtGui.QPushButton('Edit')
grid = QtGui.QGridLayout()
grid.setContentsMargins(0, 0, 0, 0)
grid.addWidget(self.uiItems, 0, 0)
grid.addWidget(self.uiEdit, 1, 0)
self.setLayout(grid)
self.uiItems.doubleClicked.connect(self.doubleClickedItem)
self.show()
def doubleClickedItem(self, idx):
name = idx.data(role=QtCore.Qt.DisplayRole)
model = idx.model()
model.setData(idx, 'great', role=QtCore.Qt.DisplayRole)
def create_model(self, parent):
items = [
'Cookie dough',
'Hummus',
'Spaghetti',
'Dal makhani',
'Chocolate whipped cream'
]
model = QtGui.QStandardItemModel()
model.setHorizontalHeaderLabels(['Name', 'Great'])
for item in items:
root = []
parentNode = QtGui.QStandardItem(item)
root.append(parentNode)
# add child row with 2 columns
for i in range(3):
row = []
col1 = QtGui.QStandardItem()
col1.setData('COLUMN 1', role=QtCore.Qt.DisplayRole)
row.append(col1)
col2 = QtGui.QStandardItem()
col2.setData('COLUMN 2', role=QtCore.Qt.DisplayRole)
row.append(col2)
parentNode.appendRow(row)
model.appendRow(root)
return model
def showEvent(self, event):
geom = self.frameGeometry()
geom.moveCenter(QtGui.QCursor.pos())
self.setGeometry(geom)
super(Browser, self).showEvent(event)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Escape:
# self.hide()
self.close()
event.accept()
else:
super(Browser, self).keyPressEvent(event)
def main():
app = QtGui.QApplication(sys.argv)
ex = Browser()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Connect the button’s clicked signal, retrieve the selected items via model.selectedIndexes, iterate over them and only handle those with .column()== 1 as in your doubleClickedItem function.
You can also change the SelectionBehavior to only select single items instead of complete rows.
Related
I want to change the selected radio button in group of radio button in cell table programatically.
I try to recreate table after change the status in piece object but if I have many records it becomes slow.
I have the next code:
import sys
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QHBoxLayout, QWidget, QButtonGroup, \
QRadioButton, QVBoxLayout, QPushButton, QApplication
class Piece:
def __init__(self, init, name, status):
self.init = init
self.name = name
self.status = status
class Table(QWidget):
def __init__(self, parent=None):
super(Table, self).__init__(parent)
self.debug_data()
self.fila = 0
self.init_ui()
def debug_data(self):
print("okay")
self.pieces: [Piece] = []
self.pieces.append(Piece('2021-01-11 13:52:00', 'Router 234', 1))
self.pieces.append(Piece('2021-01-11 13:55:00', 'Router AB', 0))
self.pieces.append(Piece('2021-01-11 14:00:00', 'Router A234E', 1))
self.pieces.append(Piece('2021-01-11 14:01:00', 'Router Sufle', 0,))
def _create_buttons(self):
self.buttons_layout = QHBoxLayout()
self.btn_ok_all = QPushButton("All Manual")
self.btn_no_ok_all = QPushButton("All Automatic")
self.btn_no_validate_all = QPushButton("All Hybrid")
self.buttons_layout.addWidget(self.btn_ok_all)
self.buttons_layout.addWidget(self.btn_no_ok_all)
self.buttons_layout.addWidget(self.btn_no_validate_all)
self.layout.addLayout(self.buttons_layout)
def init_ui(self):
self.createTable()
self.layout = QVBoxLayout()
self._create_buttons()
self.layout.addWidget(self.tableWidget)
self.setLayout(self.layout)
self.show()
def createTable(self):
self.tableWidget = QTableWidget()
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(
["Init Time", "Name", "Type"])
self.process_rows()
def process_rows(self):
for piece in self.pieces:
self.add_row(piece)
def add_row(self, piece):
self.tableWidget.insertRow(self.fila)
self.tableWidget.setItem(self.fila, 0, QTableWidgetItem(piece.init))
self.tableWidget.setItem(self.fila, 1, QTableWidgetItem(piece.name))
self.tableWidget.setCellWidget(self.fila, 2, self.create_group_radio_button(piece))
self.fila = self.fila + 1
def create_group_radio_button(self, piece):
layout = QHBoxLayout()
widget = QWidget(self)
widget.setLayout(layout)
number_group = QButtonGroup(widget)
manual = QRadioButton("Manual")
number_group.addButton(manual)
automatic = QRadioButton("Automatic")
number_group.addButton(automatic)
hybrid = QRadioButton("Hybrid")
number_group.addButton(hybrid)
layout.addWidget(manual)
layout.addWidget(automatic)
layout.addWidget(hybrid)
if piece.status == 0:
hybrid.setChecked(True)
elif piece.status == 1:
manual.setChecked(True)
else:
automatic.setChecked(True)
return widget
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Table()
sys.exit(app.exec_())
What is the way to change one of them programatically?
How to access the cell widget and select the button to change it?
This is a situation for which creating a class is probably the best approach: it improves the object structure and allows creation of functions that give easier access to it.
class PieceSelector(QWidget):
def __init__(self, piece):
super().__init__()
self.piece = piece
layout = QHBoxLayout(self)
self.number_group = QButtonGroup(self)
manual = QRadioButton("Manual", 1)
self.number_group.addButton(manual)
automatic = QRadioButton("Automatic", 2)
self.number_group.addButton(automatic)
hybrid = QRadioButton("Hybrid", 0)
self.number_group.addButton(hybrid)
layout.addWidget(manual)
layout.addWidget(automatic)
layout.addWidget(hybrid)
self.number_group.button(piece.status).setChecked(True)
def get_status(self):
return self.number_group.checkedId()
def set_status(self, status):
self.number_group.button(status).setChecked(True)
Then you just add the widget by creating the instance and get it back using cellWidget():
def add_row(self, piece):
row = self.tableWidget.rowCount()
self.tableWidget.insertRow(row)
self.tableWidget.setItem(row, 0, QTableWidgetItem(piece.init))
self.tableWidget.setItem(row, 1, QTableWidgetItem(piece.name))
self.tableWidget.setCellWidget(row, 2, PieceSelector(piece))
def set_status_for_row(self, row, status):
self.tableWidget.cellWidget(row, 2).set_status(status)
Having three classes. Class Table QTableWidget and a signal and a function to get row numbers with click event. which transmit and send to two other classes. This part of script works as promising.
class Table(QtWidgets.QWidget):
rownumber = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(Table, self).__init__(parent)
self.tableWidget = QtWidgets.QTableWidget(0, 3)
self.tableWidget.cellClicked.connect(self.cellClick)
def cellClick(self, row, column):
self.rownumber.emit(row)
def currentrow(self):
return self.tableWidget.currentRow()
Second Combo class with QComboBox and a signal and two functions to send and transfer information to third class, that value in QComboBox is changed. To check if the signal is emitting, printing Signal emitted . This part of script seems also working fine, since print code is executed.
class Combo(QtWidgets.QWidget):
Toupdatedata = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(Combo, self).__init__(parent)
self.combo = QtWidgets.QComboBox()
self.combo.addItems(["1","2","3","4"])
self.combo.activated.connect(self.setdatastrength)
#QtCore.pyqtSlot(int)
def setdatastrength(self, index):
value = self.combo[index]
self.dataupdate()
def dataupdate(self):
self.Toupdatedata.emit()
print('Signal emitted')
def get_data(self):
return tuple([self.combo.currentText()])
Third class Tab with QTabWidget and two functions and a connection, first function recieves numbers of row from first class Table, second function should and supposed to run and execute, when index of combobox from second class Combo changes. Checking to see if it works printing a string text I am executing. But it does not work as expected?! When values of QComboBox changes, function updatedata() never runs!
class Tab(QtWidgets.QWidget):
def __init__(self, parent=None):
super( Tab, self).__init__()
self.tab = QtWidgets.QTabWidget()
self.Table = Table()
self.combo = [Combo(), Combo()]
self.datacombo = []
self.Row = 0
self.tab.addTab( self.Table, 'Tables')
self.Table.rownumber.connect(self.rowselected_tables)
self.combo[self.Row].Toupdatedata.connect(self.updatedata)
# Alternative calling function currentrow.
# self.combo[self.Table.currentrow()].Toupdatedata.connect(self.updatedata)
#QtCore.pyqtSlot(int)
def rowselected_tables(self, row):
self.Row = row
if row > 0:
self.Tab.addTab(self.combo[row], 'Combo')
a1 = self.combo[row].get_data()
self.datacombo[row] = a1
#QtCore.pyqtSlot()
def updatedata(self):
self.datacombo[self.Table.currentrow()] = self.combo[self.Table.currentrow()].get_data()
print('I am executing', self.datagroup)
I wonder, what's it I'm doing wrong?
UPDATE:
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
class Table(QtWidgets.QWidget):
rownumber = QtCore.pyqtSignal(int)
rowCount = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(Table, self).__init__(parent)
self.tableWidget = QtWidgets.QTableWidget(3, 3)
self.lay = QtWidgets.QHBoxLayout(self)
self.lay.addWidget(self.tableWidget)
self.tableWidget.cellClicked.connect(self.cellClick)
def cellClick(self, row, column):
self.rownumber.emit(row)
def currentrow(self):
return self.tableWidget.currentRow()
def getrow(self):
count = self.tableWidget.rowCount()
self.rowCount.emit(count)
class Combo(QtWidgets.QWidget):
Toupdatedata = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(Combo, self).__init__(parent)
self.combo = QtWidgets.QComboBox()
self.combo.addItems(["1","2","3","4"])
self.hbox = QtWidgets.QHBoxLayout()
self.con = QtWidgets.QLabel("Number: ")
self.hbox.addWidget(self.con)
self.hbox.addWidget(self.combo)
self.setLayout(self.hbox)
self.combo.activated.connect(self.setdatastrength)
#QtCore.pyqtSlot(int)
def setdatastrength(self, index):
self.dataupdate()
def dataupdate(self):
self.Toupdatedata.emit()
print('Signal emitted')
def get_data(self):
return tuple([self.combo.currentText()])
class Tab(QtWidgets.QWidget):
def __init__(self, parent=None):
super( Tab, self).__init__()
self.tab = QtWidgets.QTabWidget()
self.Table = Table()
self.combo = []
self.datacombo = []
self.Row = 0
self.tab.addTab( self.Table, 'Tables')
self.Table.rowCount.connect(self.addrow)
self.Table.getrow()
self.Table.rownumber.connect(self.rowselected_tables)
self.combo[self.Row].Toupdatedata.connect(self.updatedata)
self.lay = QtWidgets.QHBoxLayout(self)
self.lay.addWidget(self.tab)
# Alternative calling function currentrow.
# self.combo[self.Table.currentrow()].Toupdatedata.connect(self.updatedata)
#QtCore.pyqtSlot(int)
def addrow(self, count):
for row in range(count):
self.combo.append(Combo())
self.datacombo.append(Combo().get_data())
#QtCore.pyqtSlot(int)
def rowselected_tables(self, row):
self.Row = row
if row > 0:
while self.tab.count() > 1:
self.tab.removeTab( self.tab.count()-1 )
self.tab.addTab(self.combo[row], 'Combo')
a1 = self.combo[row].get_data()
self.datacombo[row] = a1
else:
for n in [1]:
self.tab.removeTab( n )
#QtCore.pyqtSlot()
def updatedata(self):
self.datacombo[self.Table.currentrow()] = self.combo[self.Table.currentrow()].get_data()
print('I am executing', self.datagroup)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Tab()
w.show()
sys.exit(app.exec_())
In my opinion, you are connecting the signal self.combo[self.Row].Toupdatedata.connect (self.updatedata) in the wrong place.
I noted the text where the changes were made. Try it:
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
class Table(QtWidgets.QWidget):
rownumber = QtCore.pyqtSignal(int)
rowCount = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(Table, self).__init__(parent)
self.tableWidget = QtWidgets.QTableWidget(3, 3)
self.lay = QtWidgets.QHBoxLayout(self)
self.lay.addWidget(self.tableWidget)
self.tableWidget.cellClicked.connect(self.cellClick)
def cellClick(self, row, column):
self.rownumber.emit(row)
def currentrow(self):
return self.tableWidget.currentRow()
def getrow(self):
count = self.tableWidget.rowCount()
self.rowCount.emit(count)
class Combo(QtWidgets.QWidget):
Toupdatedata = QtCore.pyqtSignal(int) # + int
def __init__(self, rowTable, parent=None): # + rowTable
super(Combo, self).__init__(parent)
self.rowTable = rowTable # +
## print(rowTable, '------')
self.combo = QtWidgets.QComboBox()
self.combo.addItems(["item1", "item2", "item3", "item4"])
self.hbox = QtWidgets.QHBoxLayout()
self.con = QtWidgets.QLabel("Number: ")
self.hbox.addWidget(self.con)
self.hbox.addWidget(self.combo)
self.setLayout(self.hbox)
self.combo.activated.connect(self.setdatastrength)
#QtCore.pyqtSlot(int)
def setdatastrength(self, index):
self.dataupdate()
def dataupdate(self):
print('+ Signal emitted ->', self.rowTable)
self.Toupdatedata.emit(self.rowTable) # + self.rowTable
def get_data(self):
return tuple([self.combo.currentText()])
class Tab(QtWidgets.QWidget):
def __init__(self, parent=None):
super( Tab, self).__init__()
self.tab = QtWidgets.QTabWidget()
self.Table = Table()
self.combo = []
self.datacombo = []
self.Row = 0
self.tab.addTab( self.Table, 'Tables')
self.Table.rowCount.connect(self.addrow)
self.Table.getrow()
self.Table.rownumber.connect(self.rowselected_tables)
#- self.combo[self.Row].Toupdatedata.connect(self.updatedata)
self.lay = QtWidgets.QHBoxLayout(self)
self.lay.addWidget(self.tab)
# Alternative calling function currentrow.
# ? self.combo[self.Table.currentrow()].Toupdatedata.connect(self.updatedata)
#QtCore.pyqtSlot(int)
def addrow(self, count):
for row in range(count):
cb = Combo(row) # + row
self.combo.append(cb)
self.datacombo.append(cb.get_data()[0]) # get_data()[0]
self.combo[row].Toupdatedata.connect(lambda rowTable=row: self.updatedata(rowTable)) # <===== !!!
#QtCore.pyqtSlot(int)
def rowselected_tables(self, row):
self.Row = row
if row > 0:
while self.tab.count() > 1:
self.tab.removeTab( self.tab.count()-1 )
self.tab.addTab(self.combo[row], 'Combo')
a1 = self.combo[row].get_data()[0] # + [0]
self.datacombo[row] = a1
else:
for n in [1]:
self.tab.removeTab( n )
#QtCore.pyqtSlot()
def updatedata(self, rowTable): # + rowTable
# self.datacombo[self.Table.currentrow()] = self.combo[self.Table.currentrow()].get_data()
self.datacombo[rowTable] = self.combo[rowTable].get_data()[0] # [0]
print('I am executing', self.datacombo ) # ? self.datagroup
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Tab()
w.show()
sys.exit(app.exec_())
I have a number of QTreeWidget. Here, there are two trees.
the left one has "a" , "b".
I want to drag this item into the right tree.
I have no error but the item become empty.
How should I do for dragging the left data to the right tree?
and why?
data is this.
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x00\x02\x00a\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x00\x02\x00b'
from PySide import QtCore
from PySide import QtGui
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=None)
self.sequoia = Sequoia()
self.baobab = Baobab()
self.c_widget = QtGui.QWidget()
h_boxlayout = QtGui.QHBoxLayout()
h_boxlayout.addWidget(self.sequoia, 30)
h_boxlayout.addWidget(self.baobab, 70)
self.c_widget.setLayout(h_boxlayout)
self.setCentralWidget(self.c_widget)
class Sequoia(QtGui.QTreeWidget):
def __init__(self, parent=None):
super(Sequoia, self).__init__(parent=None)
self.setColumnCount(2)
self.setAcceptDrops(True)
self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
self.sampleitem = QtGui.QTreeWidgetItem()
self.sampleitem.setText(0, "a")
self.sampleitem.setText(1, "b")
self.addTopLevelItem(self.sampleitem)
class Baobab(QtGui.QTreeWidget):
def __init__(self, parent=None):
super(Baobab, self).__init__(parent=None)
self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
self.setColumnCount(2)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'):
event.accept()
return QtGui.QTreeWidget.dragEnterEvent(self, event)
def dragMoveEvent(self, event):
if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist') and not isinstance(event, QtGui.QDropEvent):
event.accept()
return QtGui.QTreeWidget.dragMoveEvent(self, event)
def dropEvent(self, event):
if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'):
bytearray = event.mimeData().data('application/x-qabstractitemmodeldatalist')
datastream = QtCore.QDataStream(bytearray, QtCore.QIODevice.ReadOnly)
print(3306, bytearray.data())
item = QtGui.QTreeWidgetItem()
item.setFlags(QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsEnabled|QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemIsDragEnabled|QtCore.Qt.ItemIsDropEnabled)
item.read(datastream)
self.addTopLevelItem(item)
def main():
try:
QtGui.QApplication([])
except Exception as e:
print(e)
mw = MainWindow()
mw.show()
sys.exit(QtGui.QApplication.exec_())
if __name__ == "__main__":
main()
It is not necessary to implement your own drag-and-drop method between in QTreeWidget, you just have to configure it correctly:
from PySide import QtCore, QtGui
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=None)
self.sequoia = Sequoia()
self.baobab = Baobab()
self.c_widget = QtGui.QWidget()
h_boxlayout = QtGui.QHBoxLayout(self.c_widget)
self.setCentralWidget(self.c_widget)
h_boxlayout.addWidget(self.sequoia, 30)
h_boxlayout.addWidget(self.baobab, 70)
class Sequoia(QtGui.QTreeWidget):
def __init__(self, parent=None):
super(Sequoia, self).__init__(parent=None)
self.setColumnCount(2)
self.setDefaultDropAction(QtCore.Qt.CopyAction)
self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
self.setAcceptDrops(True)
self.sampleitem = QtGui.QTreeWidgetItem()
self.sampleitem.setText(0, "a")
self.sampleitem.setText(1, "b")
self.addTopLevelItem(self.sampleitem)
class Baobab(QtGui.QTreeWidget):
def __init__(self, parent=None):
super(Baobab, self).__init__(parent=None)
self.setColumnCount(2)
self.setAcceptDrops(True)
def main():
app = QtGui.QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
If you still want to implement it manually then if we use your perspective a possible solution is:
def dropEvent(self, event):
if event.mimeData().hasFormat(
"application/x-qabstractitemmodeldatalist"
):
ba = event.mimeData().data(
"application/x-qabstractitemmodeldatalist"
)
ds = QtCore.QDataStream(
ba, QtCore.QIODevice.ReadOnly
)
i = 0
item = QtGui.QTreeWidgetItem()
while not ds.atEnd():
row = ds.readInt32()
column = ds.readInt32()
map_items = ds.readInt32()
self.addTopLevelItem(item)
for _ in range(map_items):
role = ds.readInt32()
value = ds.readQVariant()
item.setData(i, role, value)
i = (i + 1) % self.columnCount()
But the above is forced, a better solution is to use the dropMimeData method of the model:
def dropEvent(self, event):
if event.mimeData().hasFormat(
"application/x-qabstractitemmodeldatalist"
):
parent = self.indexAt(event.pos())
self.model().dropMimeData(
event.mimeData(), event.dropAction(), 0, 0, parent
)
I want to create a table in PyQt5 that has a combobox in each column header. When I try to do it, the following error is returned:
TypeError: setHorizontalHeaderItem(self, int, QTableWidgetItem): argument 2 has unexpected type 'QComboBox'
Apparently the function setHorizontalHeaderItem() doesn't accept widgets as items. So is there a way to achieve this? If not, I would settle with putting the comboboxes above the headers, but they should be aligned with the size of each column, even if the user changes the width with the mouse. I don't know if this is possible either.
My code:
from PyQt5 import QtWidgets
import numpy as np
class App(QtWidgets.QWidget):
def __init__(self):
super(App,self).__init__()
self.data = np.random.rand(5,5)
self.createTable()
self.layout = QtWidgets.QVBoxLayout()
self.layout.addWidget(self.table)
self.setLayout(self.layout)
self.showMaximized()
def createTable(self):
self.header = []
self.table = QtWidgets.QTableWidget(len(self.data), len(self.data[0]))
for i in range(len(self.data[0])):
self.header.append(QtWidgets.QComboBox())
self.header[-1].addItem('Variable')
self.header[-1].addItem('Timestamp')
self.table.setHorizontalHeaderItem(i,self.header[-1])
for i in range(len(self.data)):
for j in range(len(self.data[0])):
self.table.setItem(i,j,QtWidgets.QTableWidgetItem(str(self.data[i][j])))
if __name__ == '__main__':
app = QtWidgets.QApplication([])
ex = App()
app.exec_()
QHeaderView does not support widgets as items so you must create a custom header as I show below:
from PyQt5 import QtCore, QtWidgets
import numpy as np
class HorizontalHeader(QtWidgets.QHeaderView):
def __init__(self, values, parent=None):
super(HorizontalHeader, self).__init__(QtCore.Qt.Horizontal, parent)
self.setSectionsMovable(True)
self.comboboxes = []
self.sectionResized.connect(self.handleSectionResized)
self.sectionMoved.connect(self.handleSectionMoved)
def showEvent(self, event):
for i in range(self.count()):
if i < len(self.comboboxes):
combo = self.comboboxes[i]
combo.clear()
combo.addItems(["Variable", "Timestamp"])
else:
combo = QtWidgets.QComboBox(self)
combo.addItems(["Variable", "Timestamp"])
self.comboboxes.append(combo)
combo.setGeometry(self.sectionViewportPosition(i), 0, self.sectionSize(i)-4, self.height())
combo.show()
if len(self.comboboxes) > self.count():
for i in range(self.count(), len(self.comboboxes)):
self.comboboxes[i].deleteLater()
super(HorizontalHeader, self).showEvent(event)
def handleSectionResized(self, i):
for i in range(self.count()):
j = self.visualIndex(i)
logical = self.logicalIndex(j)
self.comboboxes[i].setGeometry(self.sectionViewportPosition(logical), 0, self.sectionSize(logical)-4, self.height())
def handleSectionMoved(self, i, oldVisualIndex, newVisualIndex):
for i in range(min(oldVisualIndex, newVisualIndex), self.count()):
logical = self.logicalIndex(i)
self.comboboxes[i].setGeometry(self.ectionViewportPosition(logical), 0, self.sectionSize(logical) - 5, height())
def fixComboPositions(self):
for i in range(self.count()):
self.comboboxes[i].setGeometry(self.sectionViewportPosition(i), 0, self.sectionSize(i) - 5, self.height())
class TableWidget(QtWidgets.QTableWidget):
def __init__(self, *args, **kwargs):
super(TableWidget, self).__init__(*args, **kwargs)
header = HorizontalHeader(self)
self.setHorizontalHeader(header)
def scrollContentsBy(self, dx, dy):
super(TableWidget, self).scrollContentsBy(dx, dy)
if dx != 0:
self.horizontalHeader().fixComboPositions()
class App(QtWidgets.QWidget):
def __init__(self):
super(App,self).__init__()
self.data = np.random.rand(10, 10)
self.createTable()
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.table)
self.showMaximized()
def createTable(self):
self.header = []
self.table = TableWidget(*self.data.shape)
for i, row_values in enumerate(self.data):
for j, value in enumerate(row_values):
self.table.setItem(i, j, QtWidgets.QTableWidgetItem(str(value)))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
If i click on any of the edit buttons, how do I get the contents of cells in the same row?
class EditButtonsWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(EditButtonsWidget,self).__init__(parent)
btnsave = QtGui.QPushButton('Save')
btnedit = QtGui.QPushButton('edit')
btndelete = QtGui.QPushButton('delete')
layout = QtGui.QHBoxLayout()
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
layout.addWidget(btnsave)
layout.addWidget(btnedit)
layout.addWidget(btndelete)
self.setLayout(layout)
class MainForm(QDialog):
def __init__(self,parent=None):
super(MainForm,self).__init__(parent)
self.resize(400,200)
self.tableWidget = QTableWidget()
layout = QVBoxLayout()
layout.addWidget( self.tableWidget)
self.setLayout(layout)
self.init_main_form()
def bb(self):
button = QtGui.QApplication.focusWidget()
index = self.tableWidget.indexAt(button.pos())
if index.isValid():
print(index.row(), index.column())
def init_main_form(self):
data =[['a','b','c','d'],['z','y','x','w']]
self.tableWidget.setColumnCount(5)
for row in data:
inx = data.index(row)
self.tableWidget.insertRow(inx)
self.tableWidget.setItem(inx,0,QTableWidgetItem(str(row[0])))
self.tableWidget.setItem(inx,1,QTableWidgetItem(str(row[1])))
self.tableWidget.setItem(inx,2,QTableWidgetItem(str(row[2])))
self.tableWidget.setItem(inx,3,QTableWidgetItem(str(row[3])))
self.tableWidget.setCellWidget(inx,4,EditButtonsWidget())
def main():
app = QApplication(sys.argv)
main_form = MainForm()
main_form.show()
app.exec_()
if __name__ == '__main__':
main()
Implemented signals and slots and now you will get idea how you can handle it
And mixing imports is not really a good idea
from PyQt4 import QtCore, QtGui
import sys
class EditButtonsWidget(QtGui.QWidget):
editCalled = QtCore.pyqtSignal(str)
def __init__(self, row, col, parent=None,):
super(EditButtonsWidget,self).__init__(parent)
self.row = row
self.col = col
self.parent = parent
btnsave = QtGui.QPushButton('Save')
btnedit = QtGui.QPushButton('edit')
btndelete = QtGui.QPushButton('delete')
layout = QtGui.QHBoxLayout()
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
layout.addWidget(btnsave)
layout.addWidget(btnedit)
layout.addWidget(btndelete)
self.setLayout(layout)
btnedit.clicked.connect(self.getAllCellVal)
#QtCore.pyqtSlot()
def getAllCellVal(self):
itmVal = {}
for col in range(0, 4):
itm = self.parent.item(self.row, col).text()
itmVal[col] = str(itm)
if itmVal:
self.editCalled.emit(str(itmVal))
class MainForm(QtGui.QDialog):
def __init__(self,parent=None):
super(MainForm,self).__init__(parent)
self.resize(400,200)
self.tableWidget = QtGui.QTableWidget()
layout = QtGui.QVBoxLayout()
layout.addWidget( self.tableWidget)
self.setLayout(layout)
self.init_main_form()
def bb(self):
button = QtGui.QApplication.focusWidget()
index = self.tableWidget.indexAt(button.pos())
if index.isValid():
print(index.row(), index.column())
def printEditVal(self, values):
print values
def init_main_form(self):
data =[['a','b','c','d'],['z','y','x','w']]
self.tableWidget.setColumnCount(5)
for row in data:
inx = data.index(row)
self.tableWidget.insertRow(inx)
self.tableWidget.setItem(inx,0,QtGui.QTableWidgetItem(str(row[0])))
self.tableWidget.setItem(inx,1,QtGui.QTableWidgetItem(str(row[1])))
self.tableWidget.setItem(inx,2,QtGui.QTableWidgetItem(str(row[2])))
self.tableWidget.setItem(inx,3,QtGui.QTableWidgetItem(str(row[3])))
buttonWid = EditButtonsWidget(inx,4, self.tableWidget)
buttonWid.editCalled.connect(self.printEditVal)
self.tableWidget.setCellWidget(inx,4,buttonWid)
def main():
app = QtGui.QApplication(sys.argv)
main_form = MainForm()
main_form.show()
app.exec_()
if __name__ == '__main__':
main()