Как добавить кнопки в ячейку таблицы QTableWidget
UPD: Ответ найден
Использую PyQt6 и следующий код:
pushButton = QtWidgets.QPushButton('Кнопка')
self.tableMain.setCellWidget(0, 8, pushButton)
Ошибок никаких не вылетает, но при выполнении просто зависает окно и кнопка (точнее просто белый прямоугольник улетает вверх монитора) и больше ничего не работает.
Кусочек скриншота прикрепляю.
Дополнительно, есть ли в PyQt6 возможность использовать несколько кнопок в одной ячейке QTableWidget?
Минимальный код следующий:
main.py
import sys
import time
from PyQt6 import QtWidgets
from table import Ui_MainWindow
from threading import Thread
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
th = Thread(target=self.insertInTable, args=())
th.start()
def insertInTable(self):
for i in range(0, 3):
rowPosition = self.tableWidget.rowCount()
self.tableWidget.insertRow(rowPosition)
cell1 = QtWidgets.QTableWidgetItem('1 ячейка')
cell2 = QtWidgets.QTableWidgetItem('2 ячейка')
self.tableWidget.setItem(rowPosition, 0, cell1)
self.tableWidget.setItem(rowPosition, 1, cell2)
pushButton = QtWidgets.QPushButton('Кнопка')
self.tableWidget.setCellWidget(rowPosition, 2, pushButton)
time.sleep(2)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
table.py
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(526, 255)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(8, 8, 509, 187))
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(3)
self.tableWidget.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(2, item)
self.tableWidget.horizontalHeader().setVisible(True)
self.tableWidget.horizontalHeader().setDefaultSectionSize(140)
self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.tableWidget.verticalHeader().setVisible(False)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 526, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
item = self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Новый столбец"))
item = self.tableWidget.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "1 столбец"))
item = self.tableWidget.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "3 столбец"))
Во время создания минимального кода - найдена проблема. Если использовать Thread, то результат в режиме Debag такой же, как и у меня в основном коде.
Переделал с использованием QThread и получил следующий код:
main.py
import sys
import time
from PyQt6 import QtWidgets, QtCore
from table import Ui_MainWindow
from PyQt6.QtCore import QThread
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.th = insertInTable()
self.th.mysignal.connect(self.insertCell)
self.th.start()
def insertCell(self):
rowPosition = window.tableWidget.rowCount()
window.tableWidget.insertRow(rowPosition)
cell1 = QtWidgets.QTableWidgetItem('1 ячейка')
cell2 = QtWidgets.QTableWidgetItem('2 ячейка')
window.tableWidget.setItem(rowPosition, 0, cell1)
window.tableWidget.setItem(rowPosition, 1, cell2)
pushButton = QtWidgets.QPushButton('Кнопка')
window.tableWidget.setCellWidget(rowPosition, 2, pushButton)
class insertInTable(QThread):
mysignal = QtCore.pyqtSignal()
def __init__(self, parent=None):
QtCore.QThread.__init__(self, parent)
def run(self):
for i in range(0, 3):
self.mysignal.emit()
time.sleep(2)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
С Python работаю всего дней 10 (как хобби), поэтому если есть явные ошибки в коде, можете смело на них указывать. Всем спасибо!
Ответы (1 шт):
Вам не нужен дополнительный поток, т.к. нельзя использовать виджеты в дополнительном потоке. Не используйте time.sleep(2) - это только замораживает интерфейс и ничего более.
import sys
#import time
'''
from PyQt6 import QtCore, QtGui, QtWidgets
'''
from PyQt5 import QtCore, QtGui, QtWidgets
#from threading import Thread
#from table import Ui_MainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(526, 255)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(8, 8, 509, 187))
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(3)
self.tableWidget.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(2, item)
self.tableWidget.horizontalHeader().setVisible(True)
self.tableWidget.horizontalHeader().setDefaultSectionSize(140)
self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.tableWidget.verticalHeader().setVisible(False)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 526, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
item = self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Новый столбец"))
item = self.tableWidget.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "1 столбец"))
item = self.tableWidget.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "3 столбец"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
'''
th = Thread(target=self.insertInTable, args=())
th.start()
'''
self.insertInTable()
def insertInTable(self): # +++
for i in range(0, 3):
rowPosition = self.tableWidget.rowCount()
self.tableWidget.insertRow(rowPosition)
cell1 = QtWidgets.QTableWidgetItem(f'ячейка {i}:1 ячейка')
cell2 = QtWidgets.QTableWidgetItem(f'ячейка {i}:2 ячейка')
self.tableWidget.setItem(rowPosition, 0, cell1)
self.tableWidget.setItem(rowPosition, 1, cell2)
pushButton = QtWidgets.QPushButton(f'Кнопка {i+1}')
pushButton.clicked.connect(
lambda ch, btn=pushButton: print(btn.text()))
self.tableWidget.setCellWidget(rowPosition, 2, pushButton)
# time.sleep(2)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Update
В случае кода, который я предоставил
sleepиспользовал лишь для того, чтобы эмитировать задержку на запросы и ожидание ответа, которые делает главная программа.
Из-за запросов и использую дополнительный поток, т.к. без потока долго ждать запуска программы, если например в таблице будет30строк и по каждой будет сделан запрос.
Не используйте time.sleep(2) - это только замораживает интерфейс и ничего более.
Класс QTimer предоставляет повторяющиеся и однократные таймеры.
Больше https://doc.qt.io/qt-5/qtimer.html
Если вам надо рабатать с потоками, вам надо лучше рассказать, что вы делаете в потоках и и какую информацию из дополнительного потока вы собираетесь передавать в основной поток.
Больше https://doc.qt.io/qt-5/signalsandslots.html
import sys
#import time
'''
from PyQt6 import QtCore, QtGui, QtWidgets
'''
from PyQt5 import QtCore, QtGui, QtWidgets
#from threading import Thread
#from table import Ui_MainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(526, 255)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(8, 8, 509, 187))
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(3)
self.tableWidget.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(2, item)
self.tableWidget.horizontalHeader().setVisible(True)
self.tableWidget.horizontalHeader().setDefaultSectionSize(140)
self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.tableWidget.verticalHeader().setVisible(False)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 526, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
item = self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Новый столбец"))
item = self.tableWidget.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "1 столбец"))
item = self.tableWidget.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "3 столбец"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
'''
th = Thread(target=self.insertInTable, args=())
th.start()
'''
# self.insertInTable()
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.insertInTable)
self.timer.start(100) # установите интервал какой вам нравится
self.i = 0
def insertInTable(self):
# for i in range(0, 3):
rowPosition = self.tableWidget.rowCount()
self.tableWidget.insertRow(rowPosition)
cell1 = QtWidgets.QTableWidgetItem(f'ячейка {self.i}:1 ячейка')
cell2 = QtWidgets.QTableWidgetItem(f'ячейка {self.i}:2 ячейка')
self.tableWidget.setItem(rowPosition, 0, cell1)
self.tableWidget.setItem(rowPosition, 1, cell2)
pushButton = QtWidgets.QPushButton(f'Кнопка {self.i+1}')
pushButton.clicked.connect(
lambda ch, btn=pushButton: print(btn.text()))
self.tableWidget.setCellWidget(rowPosition, 2, pushButton)
self.i += 1
if self.i == 30:
self.timer.stop()
# time.sleep(2)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()


