如何仅更改单行中的部分QTableWidgetItems?
我有一个QTableWidget,里面有以下几列:
Username Password URL Status
+----------+-----------+---------+---------+
| user1 | passwd1 | url.com | OK |
| user2 | passwd2 | url.com | FAIL |
+----------+-----------+---------+---------+
在我应用程序的一个工作线程QThread
中,会发出一个信号,里面包含了表格中显示的数据。不过,这些数据需要在之后更新(特别是“状态”这一列)。
我想要能够只更新,比如说,第二行的数据。目前,我的做法是遍历表格中的所有行,然后尝试找到一个唯一的字段(比如用户名),来和软件发送的数据进行匹配。所以,如果第二行的状态需要从“失败”更新为“重试”,那么发给GUI线程的信号会包含用户名和状态字符串。接着,我会比较这两个字符串(一个来自信号,也就是QThread,另一个是当前表格中的字符串),如果匹配上了,就更新表格。希望这样说能让你明白。
问题是,我在想这样做是否可行?还有其他方法吗?我考虑过在QTableWidget中添加一个“隐藏”的列,里面放一些每个QThread生成的随机字符字符串,然后进行更新。但原则上还是一样的。
有没有人能给我一些建议?
编辑:应请求添加代码:
这是我的GUI线程代码(搜索和更新部分):
def writeToMainTable(self, param):
username = param['username']
statusText = param['statusText']
for i in xrange(self.mainTable.currentRowCount()):
if username == self.mainTable.item(i, 0).text():
found = True
activerow = i
if found:
if statusText is not None: self.mainTable.setItem(activerow, 3, QTableWidgetItem(statusText))
而QThread中有这样的内容:
def sendToTable(self, param): #param is a dict here as well
self.mainsig.emit(param)
2 个回答
0
看起来你在用不同的 QThread
来更新每一行,所以你可以使用一个叫 QSignalMapper
的东西,像这样:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import time, random
from PyQt4 import QtGui, QtCore
class MyThread(QtCore.QThread):
statusChanged = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(MyThread, self).__init__(parent)
self.status = None
def run(self):
time.sleep(3)
self.status = True if not self.status else False
self.statusChanged.emit()
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.tableWidget = QtGui.QTableWidget(self)
self.tableWidget.setRowCount(2)
self.tableWidget.setColumnCount(4)
self.tableWidget.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
self.signalMapper = QtCore.QSignalMapper(self)
self.signalMapper.mapped.connect(self.on_signalMapper_mapped)
for row in range(2):
status = random.getrandbits(1)
state = "Ok" if status else "Failed"
thread = MyThread(self)
thread.status = status
self.signalMapper.setMapping(thread, row)
thread.statusChanged.connect(self.signalMapper.map)
thread.start()
values = ["user", "passwd", "url.com", state]
for column, value in enumerate(values):
item = QtGui.QTableWidgetItem()
item.setText("{0}: {1}".format(row, value))
self.tableWidget.setItem(row, column, item)
self.gridLayout = QtGui.QGridLayout(self)
self.gridLayout.addWidget(self.tableWidget, 0, 0)
@QtCore.pyqtSlot(int)
def on_signalMapper_mapped(self, number):
state = "Ok" if self.signalMapper.mapping(number).status else "Failed"
item = self.tableWidget.item(number, 3)
item.setText("{0}: {1}".format(number, state))
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.resize(666, 111)
main.show()
sys.exit(app.exec_())
0
我不太确定你具体想要什么。我猜你是希望Qt帮你处理循环的部分,对吧?如果是这样的话,这里有一种方法。希望这能帮到你。
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class Main(QWidget):
def __init__(self):
super(Main, self).__init__()
self.table = Table(self)
self.change = QPushButton('Change')
layout = QHBoxLayout(self)
layout.addWidget(self.table)
layout.addWidget(self.change)
self.change.clicked.connect(self.table.updateCell)
class Table(QTableWidget):
def __init__(self, parent=None):
super(Table, self).__init__(2, 2, parent)
self.setItem(1, 0, QTableWidgetItem('test'))
self.setItem(1, 1, QTableWidgetItem('False'))
def updateCell(self):
item, = self.findItems('test', Qt.MatchExactly)
new = repr(not eval(self.item(item.row(), 1).text()))
self.item(row, 1).setText(new)
app = QApplication([])
main = Main()
main.show()
app.exec_()