How to select multiple cells of QTableWidget? - python

I am trying to pre-select multiple "individual values (or cells some would like to call em)" from the QTableWidget and I don't seem to be able to find the right method. I have tried setRangeSelect,selectRow & selectColumn, and none of the methods works.
Looking for some help. (Please see the test method for what I am trying to do)
import sys
import json
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QPushButton
from PyQt5.Qt import QTableWidgetItem, QAbstractItemView
class Demo(QWidget):
def __init__(self):
super().__init__()
self.rowTracker = []
self.initUI()
self.initQTableWidget()
def initUI(self):
self.resize(600, 600)
# populate some data
self.rows = [['a1','b1', 'c1'], ['a2','b2','c2'], ['a3','b3','c3'], ['a4','b4','c4'], ['a5','b5','c5']]
self.btn = QPushButton(self)
self.btn.move(50, 250)
self.btn.resize(150, 40)
self.btn.setText('Check')
self.btn.clicked.connect(self.test)
def initQTableWidget(self):
self.tableWidget = QTableWidget(self)
self.tableWidget.resize(self.width(), self.height()-400)
self.tableWidget.setRowCount(len(self.rows))
self.tableWidget.setColumnCount(len(self.rows[0]))
# here we will change row selection behavior to multiselection
self.tableWidget.setSelectionMode(QAbstractItemView.MultiSelection)
for row in enumerate(self.rows):
# print(row)
for col in enumerate(row[1]):
item = QTableWidgetItem()
item.setText(col[1])
self.tableWidget.setItem(row[0], col[0], item)
def test(self):
# print(dir(self.tableWidget))
self.tableWidget.select('<2nd row>', '<1st column>')
self.tableWidget.select('<3nd row>', '<2nd column>')
# self.tableWidget.setRangeSelect()
app =QApplication(sys.argv)
widget = Demo()
widget.show()
sys.exit(app.exec_())

There are the following methods:
The setSelected() method of QtableWidgetItem:
self.tableWidget.item(1, 0).setSelected(True)
self.tableWidget.item(2, 1).setSelected(True)
The select() method of QItemSelectionModel:
model = self.tableWidget.model()
selection_model = self.tableWidget.selectionModel()
selection_model.select(model.index(1, 0), QItemSelectionModel.Select)
selection_model.select(model.index(2, 1), QItemSelectionModel.Select)
The second method is general for all views that inherit from QAbstractItemView, and the first method is just a wrapper that makes QTableWidget of the second method.

Related

How do I connect three or more windows in PyQt

I have a complex program in which I need to connect multiple windows. Unfortunately, I seem to be not fully understanding the concept/steps necessary to do this so bonus points if anyone can explain the steps/process well. In my current program, I have a list of items. Once I select them by moving them over to the right list widget, I need them to go to the third window. The third window should be activated by clicking the dots on the second window. The program runs and shows the second window appropriately but the signal/slot connection of the dots button does not work. However, the rest of the code is working because if I switch the toolkit to show the third window, that part is performing as expected. My code is below, and again, no errors are being returned, but clicking the dots button on the second window does nothing.
Also, a question - do I instantiate the third window within the second class, or only within the main window? Again, struggling to fully understand the process and I will need to do this multiple more times.
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QListWidget, QLineEdit, QTextEdit, QGridLayout, QHBoxLayout, QVBoxLayout, QSizePolicy, QFileDialog, QTabWidget, QCheckBox
import PyQt5.QtGui as qtg
import glob
import os
from PyQt5.QtCore import Qt, QSettings
import inspect
from PyQt5 import QtCore
import pandas as pd
import pathlib
import pyreadstat
import json
class ThirdWindow(QWidget):
def __init__(self):
super().__init__()
self.layout = QGridLayout()
self.setLayout(self.layout)
self.allVariables = QListWidget()
self.variablesSelected = QListWidget()
#self.allVariables.insertItem(0, 'Hello')
self.layout.addWidget(self.allVariables, 1,0)
self.layout.addWidget(self.variablesSelected, 1, 1)
def setItems(self, items):
self.allVariables.clear()
for item in items:
self.allVariables.addItem(item)
class SecondWindow(QWidget):
def __init__(self):
super().__init__()
##not sure if I am supposed to instantiate this here or only in the main window class
self.thirdWindow = ThirdWindow()
self.layout = QGridLayout(self)
self.by = QLabel("By")
self.byVariables = QLineEdit()
self.byButton = QPushButton("...")
self.layout.addWidget(self.by, 1, 0)
self.layout.addWidget(self.byVariables, 2, 0)
self.layout.addWidget(self.byButton, 2, 1)
def seconddWindowConnections(self):
self.byButton.clicked.connect(self.show_third_window)
#self.buttons['Toolkit'].clicked.connect(self.show_new_window)
def show_third_window(self):
self.thirdWindow.show()
class MainWindow(QWidget):
def __init__(self):
super().__init__()
# Add a title
self.setWindowTitle("GUI Querying Program")
self.layout = QHBoxLayout()
self.setLayout(self.layout)
self.initUI()
self.setButtonConnections()
self.sw = SecondWindow()
self.tw = ThirdWindow()
def initUI(self):
subLayouts = {}
subLayouts['LeftColumn'] = QGridLayout()
self.layout.addLayout(subLayouts['LeftColumn'],1)
# Buttons
self.buttons = {}
self.buttons['addVariable'] = QPushButton('>')
self.buttons['removeVariable'] = QPushButton('<')
self.buttons['Toolkit'] = QPushButton('Toolkit')
self.variables = QListWidget()
self.selectedVariables = QListWidget()
subLayouts['LeftColumn'].addWidget(self.variables, 7,0,4,1)
subLayouts['LeftColumn'].addWidget(self.selectedVariables, 7,1,4,1)
subLayouts['LeftColumn'].addWidget(self.buttons['addVariable'], 10,0,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['removeVariable'], 10,1,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['Toolkit'], 11,1,1,1)
names = ['apple', 'banana', 'Cherry']
self.variables.insertItems(0, names)
def setButtonConnections(self):
self.buttons['addVariable'].clicked.connect(self.add_variable)
self.buttons['Toolkit'].clicked.connect(self.show_new_window)
self.buttons['Toolkit'].clicked.connect(self.add_selected_variables)
def add_variable(self):
for item in self.variables.selectedItems():
self.selectedVariables.addItem(item.clone())
def show_new_window(self):
self.sw.show()
def add_selected_variables(self):
items = []
for i in range(self.selectedVariables.count()):
items.append(self.selectedVariables.item(i).clone())
self.tw.setItems(items)
if __name__ == "__main__":
import sys
app = QApplication([])
mw = MainWindow()
mw.show()
app.exec()
The main issue with your code is that secondWindowConnections is never called so the button actually does nothing. I corrected that and fixed a few other issues I found in my example below. I left out the bits where I made no changes and all the changes I did make I made inline notes explaining them:
class SecondWindow(QWidget):
def __init__(self):
super().__init__()
self.thirdWindow = None # dont initialize until neccessary
self.thirdWindowItems = []
self.layout = QGridLayout(self)
self.by = QLabel("By")
self.byVariables = QLineEdit()
self.byButton = QPushButton("...")
self.layout.addWidget(self.by, 1, 0)
self.layout.addWidget(self.byVariables, 2, 0)
self.layout.addWidget(self.byButton, 2, 1)
self.secondWindowConnections() # Run this to setup the
# signal for the third window.
def secondWindowConnections(self): # this had a typo
self.byButton.clicked.connect(self.show_third_window)
def show_third_window(self):
if self.thirdWindow is None: # if window has been created yet
self.thirdWindow = ThirdWindow() # create window
if not self.thirdWindow.isVisible(): # if window is showing
self.thirdWindow.show() # show window
self.thirdWindow.setItems(self.thirdWindowItems) # send items to window
def send_items(self, items): # this is to collect the variable that
self.thirdWindowItems = items # move to the third window
class MainWindow(QWidget):
def __init__(self):
super().__init__()
# Add a title
self.setWindowTitle("GUI Querying Program")
self.layout = QHBoxLayout()
self.setLayout(self.layout)
self.initUI()
self.setButtonConnections()
self.sw = None # dont initialize until neccessary.
def initUI(self):
subLayouts = {}
subLayouts['LeftColumn'] = QGridLayout()
self.layout.addLayout(subLayouts['LeftColumn'],1)
self.buttons = {}
self.buttons['addVariable'] = QPushButton('>')
self.buttons['removeVariable'] = QPushButton('<')
self.buttons['Toolkit'] = QPushButton('Toolkit')
self.variables = QListWidget()
self.selectedVariables = QListWidget()
subLayouts['LeftColumn'].addWidget(self.variables, 7,0,4,1)
subLayouts['LeftColumn'].addWidget(self.selectedVariables, 7,1,4,1)
subLayouts['LeftColumn'].addWidget(self.buttons['addVariable'], 10,0,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['removeVariable'], 10,1,1,1)
subLayouts['LeftColumn'].addWidget(self.buttons['Toolkit'], 11,1,1,1)
names = ['apple', 'banana', 'Cherry']
self.variables.insertItems(0, names)
def setButtonConnections(self):
self.buttons['addVariable'].clicked.connect(self.add_variable)
self.buttons['Toolkit'].clicked.connect(self.show_new_window)
# self.buttons['Toolkit'].clicked.connect(self.add_selected_variables)
# only use one connnect slot
def add_variable(self):
for item in self.variables.selectedItems():
self.selectedVariables.addItem(item.clone())
def show_new_window(self):
if self.sw is None: # check if window has been constructed
self.sw = SecondWindow() # construct window
if not self.sw.isVisible(): # If winow is not showing
self.sw.show() # show window
self.sw.send_items(self.add_selected_variables()) # send selected
# variables to second window
def add_selected_variables(self):
items = []
for i in range(self.selectedVariables.count()):
items.append(self.selectedVariables.item(i).clone())
# self.tw.setItems(items) ... self.tw doesnt exist so return them
return items

Cannot populate QTableWidget using .setItem(row, colum, QTableWidgetItem(data))

I wanted to test PyQt to write a quick app to display and edit data in an Excel like form but the data is never shown.
Both the docs and the book I read say that using .setItem(row, colum, QTableWidgetItem(data)) on a QtableWidget object is one way to go.
However, the following code doesn't work, I only have an empty table and I can't figure out why. Any idea ?
import sys
from PyQt5.QtWidgets import (
QApplication,
QMainWindow,
QTableWidget,
QTableWidgetItem,
QMenu,
QAction,
QInputDialog,
)
class SpreadsheetFramework(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setMinimumSize(1000, 500)
self.setWindowTitle("Spreadsheet Table")
# Used for copy and paste actions
self.item_text = None
self.createTable()
self.fillTable()
self.show()
def createTable(self):
self.table_widget = QTableWidget()
self.table_widget.setRowCount(10)
self.table_widget.setColumnCount(10)
self.table_widget.setCurrentCell(0, 0)
self.setCentralWidget(self.table_widget)
def fillTable(self):
for i in range(10):
for j in range(10):
self.table_widget.setItem(i, j, QTableWidgetItem(i * j))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = SpreadsheetFramework()
sys.exit(app.exec_())
This is what the window looks like when I run the code
If you want to display the data in a QTableWidgetItem and pass it through the constructor then it must be a string.
self.table_widget.setItem(i, j, QTableWidgetItem(str(i * j)))
The downside is that it is no longer a number but a string that represents a number.
Another better option is to use setData to pass the number to the Qt.DisplayRole role.
item = QTableWidgetItem()
item.setData(Qt.DisplayRole, i * j)
self.table_widget.setItem(i, j, item)

Data not being added to table with PyQt5

My code is supposed to add data to a two column table when "add" button is clicked. The problem is that when the "add" button is clicked, only the empty row is being added. Can someone please let me know what is wrong? Below is the part of the code that adds data1 and data2 to a table on the right side of the layout. The function add_entry is where the data is being added.
# Import dependencies
from PyQt5.QtWidgets import (QWidget, QApplication, QTableWidget, QTableWidgetItem,QHBoxLayout, QVBoxLayout, QHeaderView, QPushButton, QDialog,
QLabel, QFileDialog, QMainWindow, QAction, QLineEdit)
from PyQt5.Qt import Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtChart import QChart, QChartView, QLineSeries
import sys
import pandas as pd
import math
# ------------------------------------------------------UI-main----------------------------------------------------------------------------------
# Creates a QApplication instance
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.items=0
# Creates table on the left size
self.table_l = QTableWidget()
self.table_l.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# Creates layout object for the right side
self.layoutRight = QVBoxLayout()
# Creates chart widget
self.chartView = QChartView()
# Smooths the edge of the chart
self.chartView.setRenderHint(QPainter.Antialiasing)
# Creates table on the right size
self.table_r = QTableWidget()
self.table_r.setColumnCount(2)
# self.table_r.setRowCount()
self.table_r.setHorizontalHeaderLabels(('Data1', 'Data2'))
self.table_r.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.table_r.setMaximumSize(600, 300)
self.lineEditData1 = QLineEdit()
self.lineEditData2 = QLineEdit()
# Create push buttons
self.buttonAdd = QPushButton('Add')
self.buttonClear = QPushButton('Clear')
self.buttonQuit = QPushButton('Quit')
self.buttonAdd.setEnabled(False)
self.layoutRight.setSpacing(10)
self.layoutRight.addWidget(self.table_r, 50)
self.layoutRight.addWidget(QLabel('data1'))
self.layoutRight.addWidget(self.lineEditData1)
self.layoutRight.addWidget(QLabel('data2'))
self.layoutRight.addWidget(self.lineEditData2)
self.layoutRight.addWidget(self.buttonAdd)
self.layout = QHBoxLayout()
self.layout.addWidget(self.table_l, 50)
self.setLayout(self.layout)
self.layout.addLayout(self.layoutRight, 50)
# Connect button to function functions
self.buttonQuit.clicked.connect(lambda:app.quit())
self.buttonAdd.clicked.connect(self.add_entry)
self.buttonClear.clicked.connect(self.reset_table)
self.lineEditData1.textChanged[str].connect(self.check_disable)
self.lineEditData2.textChanged[str].connect(self.check_disable)
def add_entry(self):
Data1 = self.lineEditData1.text()
Data2 = self.lineEditData2.text()
try:
Data1Item = QTableWidgetItem(int(Data1))
Data2Item = QTableWidgetItem(float(Data2))
Data2Item.setTextAlignment(Qt.AlignRight | Qt.AlignCenter)
self.table_r.insertRow(self.items)
self.table_r.setItem(self.items, 0, Data1Item)
self.table_r.setItem(self.items, 1, Data2Item)
self.items +=1
# after passing the item, clear the field by entering an empty string
self.lineEditData1.setText('')
self.lineEditData2.setText('')
except ValueError:
pass
# Creates main window object instance
class MainWindow(QMainWindow):
def __init__(self, widget):
super().__init__()
self.setWindowTitle('test')
self.resize(1200, 1200)
self.menuBar = self.menuBar()
self.fileMenu = self.menuBar.addMenu('File')
# import wind speed data
importAction = QAction('Open File', self)
importAction.setShortcut('Ctrl+O')
# exit action
exitAction = QAction('Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(lambda: app.quit())
self.fileMenu.addAction(importAction)
self.fileMenu.addAction(exitAction)
self.setCentralWidget(widget)
if __name__ =='__main__':
# don't auto scale when drag app to a different monitor
#QGuiApplication.setHightDpiScaleFactorRoundingPolicy(Qt.HightDpiScaleFactorRoundingPolicy.PassThrough)
app = QApplication(sys.argv)
w = MyApp()
demo = MainWindow(w)
demo.show()
try:
sys.exit(app.exec())
except SystemExit:
print('Closing window...')
The objective of exceptions is not to hide errors but to know how to prevent them, so they must be as small as possible so as not to hide other errors. In this case, QTableWidgetItem accepts a string as an argument and not numerical values, therefore an exception is thrown preventing the code that adds the items from being executed. The solution is to use the setData() method of the QTableWidgetItem:
def add_entry(self):
data1 = self.lineEditData1.text()
data2 = self.lineEditData2.text()
try:
value1 = int(data1)
value2 = float(data2)
except ValueError:
print("failed conversion")
return
else:
data1_item = QTableWidgetItem()
data1_item.setData(Qt.DisplayRole, value1)
data2_item = QTableWidgetItem()
data2_item.setData(Qt.DisplayRole, value2)
data2_item.setTextAlignment(Qt.AlignRight | Qt.AlignCenter)
row = self.table_r.rowCount()
self.table_r.insertRow(row)
self.table_r.setItem(row, 0, data1_item)
self.table_r.setItem(row, 1, data2_item)
self.lineEditData1.clear()
self.lineEditData2.clear()

Python PyQt5 CreateTable class inheriting QtWidgets.QTableWidget to add add_row function

I am trying to create an application with a table in it to display rows of data. When more data arrives, I'd like to add a row and enter the data. However, I'm stuck at adding the row. Also, my own CreateTable class that inherits QtWidgets.QTableWidget works, but I don't understand why the line
self = QTableWidget(win)
is required. I've tried to keep the code as simple as possible just now until I get round having the table as an object with custom functions (add_row, delete_row...). Here is my code:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem
import sys
class CreateTable(QTableWidget):
def __init__(self, win):
super().__init__()
# Doesn't display table without the next line. I don't understand why it is required.
self = QTableWidget(win)
#
self.setGeometry(50, 50, 1820, 920)
self.setRowCount(10)
self.setColumnCount(10)
def add_row(self):
rowcount = self.rowCount()
self.insertRow(rowcount)
class MainWindow(QMainWindow):
def __init__(self):
"""MainWindow constructor."""
super().__init__()
# Main UI code
self.setGeometry(0, 0, 1920, 1040)
self.setWindowTitle("Order Manager")
table = CreateTable(self)
table.add_row()
# Main code
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
This code opens the window and displays a table with 10 rows, but doesn't add the row to make 11 rows. I am quite new to OOP and PyQt5, but am trying to learn more!
New working code:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem
import sys
class MainWindow(QMainWindow):
def __init__(self):
"""MainWindow constructor."""
super().__init__()
# Main UI code
self.setGeometry(0, 0, 1920, 1040)
self.setWindowTitle("Order Manager")
self.table = CreateTable(self)
self.table.add_row()
class CreateTable(QTableWidget):
def __init__(self, win):
super().__init__(win)
self.setGeometry(50, 55, 1820, 920)
self.setRowCount(10)
self.setColumnCount(10)
def add_row(self):
rowcount = self.rowCount()
self.insertRow(rowcount)
# Main code
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())

How should I connect CheckBox clicked signals in Table Widgets in PyQt5?

I would like to add various widgets to various cells in a Table Widget, and I would like to trigger commands when those widgets' values are changed. I can get the widgets into the table as desired, but I'm having problems connecting signals so that I know which widget has generated the signal.
Below is a simple example explaining the problem, using just checkboxes:
from PyQt5 import QtWidgets, QtGui, QtCore
class Main(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
# create table:
self.table = QtWidgets.QTableWidget()
[self.table.insertRow(i) for i in [0,1,2]]
[self.table.insertColumn(i) for i in [0,1]]
# set values for first column:
self.table.setItem(0, 0, QtWidgets.QTableWidgetItem('A') )
self.table.setItem(1, 0, QtWidgets.QTableWidgetItem('B') )
self.table.setItem(2, 0, QtWidgets.QTableWidgetItem('C') )
# add checkboxes to second column:
cb0 = QtWidgets.QCheckBox( parent=self.table )
cb1 = QtWidgets.QCheckBox( parent=self.table )
cb2 = QtWidgets.QCheckBox( parent=self.table )
self.table.setCellWidget(0, 1, cb0)
self.table.setCellWidget(1, 1, cb1)
self.table.setCellWidget(2, 1, cb2)
# connect table signals:
self.table.cellChanged.connect(self.cell_changed)
self.table.itemChanged.connect(self.item_changed)
# connect checkbox signals:
cb0.clicked.connect(self.checkbox_clicked)
cb1.clicked.connect(self.checkbox_clicked)
cb2.clicked.connect(self.checkbox_clicked)
# show:
self.setCentralWidget(self.table)
self.setWindowTitle('TableWidget, CheckBoxes')
self.show()
def cell_changed(self, row, col):
print(row, col)
def checkbox_clicked(self, checked):
print(checked)
def item_changed(self, item):
print(item)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = Main()
app.exec_()
Based on table.cellChanged.connect I would naively expect a cellChanged signal when the checkboxes are changed. However this signal is not generated. Nor is the itemChanged signal. I can indeed see the clicked signals, but that is not very useful because it is unclear which checkbox has produced the signal.
One way to solve the problem is to create a different checkbox_clicked function for each checkbox, but that hardly seems elegant.
My questions are:
Why is neither a cellChanged nor an itemChanged signal generated when a checkbox is changed?
How should signals be connected in order to know which checkbox has generated the clicked signal?
Why is neither a cellChanged nor an itemChanged signal generated when
a checkbox is changed?
because when you use setCellWidget() a QTableWidgetItem is not created, and if we check the documentation of cellChanged and itemChanged:
void QTableWidget::cellChanged(int row, int column)
This signal is emitted whenever the data of the item in the cell specified by row and column has changed.
void QTableWidget::itemChanged(QTableWidgetItem *item)
This signal is emitted whenever the data of item has changed.
How should signals be connected in order to know which checkbox has generated the clicked signal?
The way to obtain is indirectly, the first thing to know is that when the widget is added through the setCellWidget() method, the viewport() of the QTableWidget is set as a parent.
Also another thing that should be known is that the position of a widget that is accessed through pos() is relative to the parent, that is, in our case relative to viewport().
There is a very useful method called sender() that returns the object that emits the signal, in this case it will return the QCheckBox.
As the position of the widget with respect to the viewport() is known, its QModelIndex is accessed through the indexAt() method, the QModelIndex has the information of the cell.
All of the above is implemented in the following example:
from PyQt5 import QtWidgets, QtGui, QtCore
class Main(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
# create table:
self.table = QtWidgets.QTableWidget()
self.table.setRowCount(3)
self.table.setColumnCount(2)
for i, letter in enumerate("ABC"):
self.table.setItem(i, 0, QtWidgets.QTableWidgetItem(letter))
for i in range(self.table.rowCount()):
ch = QtWidgets.QCheckBox(parent=self.table)
ch.clicked.connect(self.onStateChanged)
self.table.setCellWidget(i, 1, ch)
self.setCentralWidget(self.table)
self.setWindowTitle('TableWidget, CheckBoxes')
self.show()
def onStateChanged(self):
ch = self.sender()
print(ch.parent())
ix = self.table.indexAt(ch.pos())
print(ix.row(), ix.column(), ch.isChecked())
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = Main()
sys.exit(app.exec_())
Another way to do it is through lambda methods or partial.functions where we pass directly new parameters.
from PyQt5 import QtWidgets, QtGui, QtCore
class Main(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
# create table:
self.table = QtWidgets.QTableWidget()
self.table.setRowCount(3)
self.table.setColumnCount(2)
for i, letter in enumerate("ABC"):
self.table.setItem(i, 0, QtWidgets.QTableWidgetItem(letter))
for i in range(self.table.rowCount()):
ch = QtWidgets.QCheckBox(parent=self.table)
ch.clicked.connect(lambda checked, row=1, col=i: self.onStateChanged(checked, row, col))
self.table.setCellWidget(i, 1, ch)
self.setCentralWidget(self.table)
self.setWindowTitle('TableWidget, CheckBoxes')
self.show()
def onStateChanged(self, checked, row, column):
print(checked, row, column)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = Main()
sys.exit(app.exec_())
If you want to know more information how to pass extra parameters through connect() you can review this answer.
use the stateChanged signal for checkboxes.
and my take about that code:
in some cases it's helpful to have a reference to checkbox widgets, for some logic actions.
use loops if possible
use explicit imports in PyQt - the class names are unique and it's more readable
for example:
from PyQt5.QtWidgets import QMainWindow, QTableWidgetItem, QCheckBox, QApplication
from typing import Dict
class Main(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
# create table:
self.table = QTableWidget()
self.table.insertColumn(0)
self.table.insertColumn(1)
self._items: Dict[QTableWidgetItem, QCheckBox] = {}
for i, tag in enumerate(['A', 'B', 'C']):
self.table.insertRow(i)
item = QTableWidgetItem(tag)
cb = QCheckBox(parent=self.table)
self._items[item] = cb
# set values for first column:
self.table.setItem(i, 0, item)
# add checkboxes to second column:
self.table.setCellWidget(i, 1, cb)
# connect cb signals:
self._items[item].stateChanged.connect(self.checkbox_clicked)
# connect table signals:
self.table.cellChanged.connect(self.cell_changed)
# show:
self.setCentralWidget(self.table)
self.setWindowTitle('TableWidget, CheckBoxes')
self.show()
def cell_changed(self, row, col):
print(row, col)
def checkbox_clicked(self, checked):
print(checked)
def item_changed(self, item):
print(item)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
main = Main()
app.exec_()

Categories

Resources