I'm trying to populate a QTableWidget with the attributes of a file opened elsewhere in the script. I've successfully set the file attributes read in from the file using the following code:
class FileHeader(object):
fileheader_fields=(
"filetype","fileversion","numframes",
"framerate","resolution","numbeams",
"samplerate","samplesperchannel","receivergain",
"windowstart","winlengthsindex","reverse",
"serialnumber","date","idstring","ID1","ID2",
"ID3","ID4","framestart","frameend","timelapse",
"recordInterval","radioseconds","frameinterval","userassigned")
fileheader_formats=(
'S3','B','i4','i4','i4','i4','f','i4','i4','i4',
'i4','i4','i4','S32','S256','i4','i4','i4','i4',
'i4','i4','i4','i4','i4','i4','S136')
IMAGE_HEADER_BYTES = 256
IMAGES_DATA_BYTES = 49152
def __init__(self,filename=''):
self.filename = filename
if filename:
self.setFile(filename)
else:
# initialize our attributes to None
for field in self.fileheader_fields:
setattr(self,field,None)
def setFile(self, f):
self.infile=open(f, 'rb')
dtype=dict(names=self.fileheader_fields, formats=self.fileheader_formats)
self.fileheader=np.fromfile(self.infile, dtype=dtype, count=1)
self.fileheader_length=self.infile.tell()
for field in self.fileheader_fields:
setattr(self,field,self.fileheader[field])
I've used this code to populate the table but I keep getting a "FileHeader has no attribute fileheader" error.
from fileheader import FileHeader, Frame
from echogram import QEchogram
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import os, sys
class MainWindow(QWidget):
def __init__(self, parent=None):
self.fileheader_fields=FileHeader.fileheader_fields
self.fileheader_values=FileHeader.fileheader[field]
self.fileheader={field: "value of" + field
for field in self.fileheader_fields}
super(MainWindow, self).__init__(parent)
self.fileheader_table=QTableWidget()
layout=QVBoxLayout()
layout.addWidget(self.fileheader_table)
self.setLayout(layout)
self.populate
def populate(self):
self.fileheader_table.setRowCount(len(self.fileheader_fields))
self.fileheader_table.sestColumnCount(2)
self.fileheader_table.setHorizontalHeaderLabels(['name','value'])
for i,field in enumerate(self.fileheader_fields):
name=QTableWidgetItem(field)
value=QTableWidgetItem(self.fileheader[field])
self.fileheader_table.setItem(i,0,name)
self.fileheader_table.setItem(i,1,value)
if __name__=="__main__":
app=QApplication(sys.argv)
filename=str(QFileDialog.getOpenFileName(None,"open file","C:/vprice/DIDSON/DIDSON Data","*.ddf"))
wnd=MainWindow()
wnd.resize(640,480)
wnd.show()
#echoGram=QEchogram()
#echoGram.initFromFile(filename)
#fileName="test.png"
#echoGram.processEchogram()
#dataH=echoGram.data
#print "Horizontal data", dataH
Bear with me-- I just started with all of the Python stuff about a month ago...
See populate method. Also there is some examples in documentation
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
self.fileheader_fields=(
"filetype","fileversion","numframes",
"framerate","resolution","numbeams",
"samplerate","samplesperchannel","receivergain",
"windowstart","winlengthsindex","reverse",
"serialnumber","date","idstring","ID1","ID2",
"ID3","ID4","framestart","frameend","timelapse",
"recordInterval","radioseconds","frameinterval","userassigned"
)
# just for test
self.fileheader = {field: 'value of ' + field
for field in self.fileheader_fields}
super(MainWindow, self).__init__(parent)
self.table_widget = QtGui.QTableWidget()
layout = QtGui.QVBoxLayout()
layout.addWidget(self.table_widget)
self.setLayout(layout)
self.populate()
def populate(self):
self.table_widget.setRowCount(len(self.fileheader_fields))
self.table_widget.setColumnCount(2)
self.table_widget.setHorizontalHeaderLabels(['name', 'value'])
for i, field in enumerate(self.fileheader_fields):
name = QtGui.QTableWidgetItem(field)
value = QtGui.QTableWidgetItem(self.fileheader[field])
self.table_widget.setItem(i, 0, name)
self.table_widget.setItem(i, 1, value)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
wnd = MainWindow()
wnd.resize(640, 480)
wnd.show()
sys.exit(app.exec_())
UPD
Code for your concrete case:
from fileheader import FileHeader, Frame
from echogram import QEchogram
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import os, sys
class MainWindow(QWidget):
def __init__(self, filename, parent=None):
super(MainWindow, self).__init__(parent)
# here we are loading file
# now self.fileheader contains attributes
self.fileheader = FileHeader(filename)
self.fileheader_table = QTableWidget()
layout = QVBoxLayout()
layout.addWidget(self.fileheader_table)
self.setLayout(layout)
self.populate()
def populate(self):
self.fileheader_table.setRowCount(len(self.fileheader.fileheader_fields))
self.fileheader_table.sestColumnCount(2)
self.fileheader_table.setHorizontalHeaderLabels(['name','value'])
for i,field in enumerate(self.fileheader.fileheader_fields):
name=QTableWidgetItem(field)
value=QTableWidgetItem(getattr(self.fileheader, field))
self.fileheader_table.setItem(i,0,name)
self.fileheader_table.setItem(i,1,value)
if __name__=="__main__":
app=QApplication(sys.argv)
filename=str(QFileDialog.getOpenFileName(None,"open file","C:/vprice/DIDSON/DIDSON Data","*.ddf"))
wnd=MainWindow(filename)
wnd.resize(640,480)
wnd.show()
#echoGram=QEchogram()
#echoGram.initFromFile(filename)
#fileName="test.png"
#echoGram.processEchogram()
#dataH=echoGram.data
#print "Horizontal data", dataH
ok u have to add a QTableWidget to your custom QtGui.QMainWindow
i would create i whith 0 line and the right amount of collumn,like this:
self.tableArea=QtGui.QTableWidget(0,self.fileheader_length,self)
self.setHorizontalHeaderLabels(['nameOne','nameTwo'])#will name your top header
self.verticalHeader().setVisible(False)#will hide your left header if you don't need them
and add your line one by one
self.tableArea.insertRow(row)#it will add a line at the row position
after that u have to create a QTableWidgetItem for each cell
itemTo=QtGui.QTableWidgetItem('text')#replace text by your value
and place your item in the cell you want
self.tableArea.setItem(row, column, itemTo)
Related
import sys
from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QApplication, QItemDelegate, QWidget, QTableWidget, QTableWidgetItem, QPushButton, QHeaderView, QHBoxLayout, QVBoxLayout
from PyQt6.QtCore import Qt
import pandas as pd
class ComboBoxDelegate(QItemDelegate):
def __init__(self, parent=None):
super(ComboBoxDelegate, self).__init__(parent)
self.items = []
def setItems(self, items):
self.items = items
def createEditor(self, widget, option, index):
editor = QtWidgets.QComboBox(widget)
editor.addItems(self.items)
return editor
def setEditorData(self, editor, index):
value = index.model().data(index, Qt.ItemDataRole.EditRole)
if value:
editor.setCurrentText(str(value))
print("Data Changed")
def setModelData(self, editor, model, index):
model.setData(index, editor.currentIndex(), Qt.ItemDataRole.EditRole)
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.window_width, self.window_height = 700, 500
self.resize(self.window_width, self.window_height)
self.setWindowTitle('Load Excel (or CSV) data to QTableWidget')
layout = QVBoxLayout()
self.setLayout(layout)
self.table = QTableWidget()
layout.addWidget(self.table)
self.button = QPushButton('&Load Data')
self.button.clicked.connect(lambda _, xl_path=excel_file_path,: self.loadExcelData(xl_path))
layout.addWidget(self.button)
def loadExcelData(self, excel_file_dir):
df = pd.read_csv(excel_file_dir)
if df.size == 0:
return
df.fillna('', inplace=True)
self.table.setRowCount(df.shape[0])
self.table.setColumnCount(df.shape[1])
self.table.setHorizontalHeaderLabels(df.columns)
# returns pandas array object
for row in df.iterrows():
values = row[1]
for col_index, value in enumerate(values):
if isinstance(value, (float, int)):
value = '{0:0,.0f}'.format(value)
tableItem = QTableWidgetItem(str(value))
self.table.setItem(row[0], col_index, tableItem)
self.create_delegate(self.table)
self.table.setColumnWidth(2, 300)
def create_delegate(self, table):
test_del = ComboBoxDelegate()
test_list = ["Gravity Main", "Manhole", "Lateral"]
test_del.setItems(test_list)
table.setItemDelegateForColumn(0, test_del)
if __name__ == '__main__':
excel_file_path = "[Your CSV]"
app = QApplication(sys.argv)
app.setStyleSheet('''
QWidget {
font-size: 17px;
}
''')
myApp = MyApp()
myApp.show()
try:
sys.exit(app.exec())
except SystemExit:
print('Closing Window...')
Extension to previous question
Change the file directory to a random csv.
This populates the QTableWidget and does the same thing as my main program.
The QTableWidget does not save the changes.
My goal is to be able to populate multiple columns with different options based on the csv that is loaded. I had a working version but using QTableView instead of QTableWidget and I am working on transferring that progress.
The issue is caused by a code generation bug, according to the PyQt maintainer.
It should have been fixed in the following PyQt6 snapshots, so it's very likely that if you do a pip update you'll get the working version already, otherwise wait a couple of days and keep an eye on the changelog of the official site.
I have 2 tabs in PyQT5 created as separate classes. 1 class (tab) is to load excel file, second to set rules for removing unneeded rows. When I load file I need to post all headers to QComboBox in other tab so I can create rules. Can't make that to work.
import sys
from PyQt5.QtWidgets import *
import pandas as pd
class BOMAppWindow(QDialog):
def __init__(self):
super().__init__()
self.setGeometry(250, 150, 1400, 600)
mainTabWidget = QTabWidget() # --------- TABS UI ----------
mainTabWidget.addTab(FileOpenTab(), "File Open")
mainTabWidget.addTab(RowRemoveRulesTab(), "Row Delete Rules")
mainVbox = QVBoxLayout()
mainVbox.addWidget(mainTabWidget)
self.setLayout(mainVbox)
df = pd.DataFrame() # pandas dataframe as container for excel spreadsheet
header_list = []
class FileOpenTab(QDialog):
def __init__(self):
super().__init__()
vbox = QVBoxLayout()
h_top_box = QHBoxLayout()
excel_load_button = QPushButton("Open Excel File")
h_top_box.addWidget(excel_load_button) # ---- Adding Widgets to HBox
# ---------------- Adding Table Widget -----------
self.excel_table = QTableWidget()
vbox.addLayout(h_top_box) #-----Create Vertical Box Layout
vbox.addWidget(self.excel_table)
self.setLayout(vbox)
excel_load_button.clicked.connect(self.set_file_data)
# ----------- Open Excel Button Clicked Event
self.show()
def file_path(self): # ----------- file dialog box
filter_excel_only = "Excel Files (*.xlsx)"
filename = QFileDialog.getOpenFileName(self, 'Open Excel File', "", filter_excel_only)
return filename[0]
def set_file_data(self):
path_text = self.file_path()
if path_text:
global df
df = pd.read_excel(path_text, na_filter=False)
self.post_dataframe(df)
RowRemoveRulesTab().update_select_list()
def post_dataframe(self, dataframe):
column_count = dataframe.shape[1]
row_count = dataframe.shape[0]
self.excel_table.setColumnCount(column_count)
self.excel_table.setRowCount(row_count)
self.excel_table.setHorizontalHeaderLabels(list(dataframe.columns))
def header_list(self):
return list(df.columns)
class RowRemoveRulesTab(QDialog):
def __init__(self):
super().__init__()
hbox = QHBoxLayout()
groupBox1 = QGroupBox("Rule 1:")
vbox1 = QVBoxLayout()
self.rule1select = QComboBox()
self.rule1select.addItems(FileOpenTab().header_list())
vbox1.addWidget(self.rule1select)
groupBox1.setLayout(vbox1)
hbox.addWidget(groupBox1)
self.setLayout(hbox)
self.show()
def update_select_list(self):
self.rule1select.clear()
self.rule1select.addItems(FileOpenTab().header_list())
print(FileOpenTab().header_list())
app = QApplication(sys.argv)
bomAppWindow = BOMAppWindow()
bomAppWindow.show()
app.exec()
I need last function in second tab (or any other way to handle it) update_select_list(self): to update QComboBox with header list from excel file loaded in first FileOpenTab class. Now QComboBox remains blank after file load.
The key point of your problem is that you assume that every time you do FileOpenTab() it will always be the same widget but it is not. The same goes for RowRemoveRulesTab. Instead you have to store the object in a variable and reuse it.
On the other hand you have design problems, in this case you must use the Single responsibility principle where it indicates that each class has a function, and must provide methods for other objects to access the information, in Qt/PyQt the simplest way of transmitting information is through signals, in this case when the dataframe is loaded a signal will be emitted with the new headers, and that signal must be connected to a method of the other class so that it updates the information of the QComboBox.
from PyQt5 import QtCore, QtGui, QtWidgets
import pandas as pd
class FileOpenTab(QtWidgets.QWidget):
headersChanged = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
super(FileOpenTab, self).__init__(parent)
excel_load_button = QtWidgets.QPushButton(
"Open Excel File", clicked=self.load_file
)
self.excel_table = QtWidgets.QTableWidget()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(excel_load_button)
lay.addWidget(self.excel_table)
#QtCore.pyqtSlot()
def load_file(self):
filter_excel_only = "Excel Files (*.xlsx)"
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
self, "Open Excel File", "", filter_excel_only
)
if filename:
df = pd.read_excel(filename, na_filter=False)
self.fill_table(df)
def fill_table(self, dataframe):
row_count, column_count = dataframe.shape
self.excel_table.setColumnCount(column_count)
self.excel_table.setRowCount(row_count)
headers = list(dataframe.columns)
self.excel_table.setHorizontalHeaderLabels(headers)
self.headersChanged.emit(headers)
class RowRemoveRulesTab(QtWidgets.QWidget):
def __init__(self, parent=None):
super(RowRemoveRulesTab, self).__init__(parent)
self.rule_select = QtWidgets.QComboBox()
group_box = QtWidgets.QGroupBox("Rule 1:")
vbox = QtWidgets.QVBoxLayout()
vbox.addWidget(self.rule_select)
group_box.setLayout(vbox)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(group_box)
#QtCore.pyqtSlot(list)
def update_items(self, items):
self.rule_select.clear()
self.rule_select.addItems(items)
class BOMAppWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(BOMAppWindow, self).__init__(parent)
file_open_tab = FileOpenTab()
row_remove_rules_tab = RowRemoveRulesTab()
file_open_tab.headersChanged.connect(row_remove_rules_tab.update_items)
mainTabWidget = QtWidgets.QTabWidget()
mainTabWidget.addTab(file_open_tab, "File Open")
mainTabWidget.addTab(row_remove_rules_tab, "Row Delete Rules")
self.setCentralWidget(mainTabWidget)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = BOMAppWindow()
w.show()
sys.exit(app.exec_())
I currently have a basic GUI right now with each page in its own file. I can navigate to and from each page with no problem, but I'm having difficulty simply passing a search query to another Widget. Here's where I setup the connections in the main file:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
import search
import watching
import helpinfo
import results
class MainWindow(QMainWindow):
def __init__(self, parent=None):
'''
Constructor
'''
QMainWindow.__init__(self, parent)
self.centralWidget = QStackedWidget()
self.setCentralWidget(self.centralWidget)
self.startScreen = Start(self)
self.searchScreen = search.Search(self)
self.watchingScreen = watching.Watching(self)
self.helpInfoScreen = helpinfo.HelpInfo(self)
self.resultsScreen = results.Results(self)
self.centralWidget.addWidget(self.startScreen)
self.centralWidget.addWidget(self.searchScreen)
self.centralWidget.addWidget(self.watchingScreen)
self.centralWidget.addWidget(self.helpInfoScreen)
self.centralWidget.addWidget(self.resultsScreen)
self.centralWidget.setCurrentWidget(self.startScreen)
self.startScreen.searchClicked.connect(lambda: self.centralWidget.setCurrentWidget(self.searchScreen))
self.startScreen.watchingClicked.connect(lambda: self.centralWidget.setCurrentWidget(self.watchingScreen))
self.startScreen.helpInfoClicked.connect(lambda: self.centralWidget.setCurrentWidget(self.helpInfoScreen))
self.searchScreen.searchSubmitted.connect(lambda: self.centralWidget.setCurrentWidget(self.resultsScreen))
self.searchScreen.passQuery.connect(lambda: self.resultsScreen.grabSearch) #This is the problem line
self.searchScreen.clicked.connect(lambda: self.centralWidget.setCurrentWidget(self.startScreen))
self.watchingScreen.clicked.connect(lambda: self.centralWidget.setCurrentWidget(self.startScreen))
self.helpInfoScreen.clicked.connect(lambda: self.centralWidget.setCurrentWidget(self.startScreen))
self.resultsScreen.clicked.connect(lambda: self.centralWidget.setCurrentWidget(self.startScreen))
Here's the search file:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class Search(QWidget):
clicked = pyqtSignal()
searchSubmitted = pyqtSignal()
passQuery = pyqtSignal(str)
def __init__(self, parent=None):
super(Search, self).__init__(parent)
logo = QLabel(self)
pixmap = QPixmap('res/logo.png')
logo.setPixmap(pixmap)
logo.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
logo.setAlignment(Qt.AlignCenter)
self.textbox = QLineEdit(self)
label = QLabel(text="This is the search page.")
label.setAlignment(Qt.AlignCenter)
button = QPushButton(text='Submit')
button.clicked.connect(lambda: self.submitSearch())
button2 = QPushButton(text='Go back.')
button2.clicked.connect(self.clicked.emit)
layout = QVBoxLayout()
layout.addWidget(logo)
layout.addWidget(label)
layout.addWidget(self.textbox)
layout.addWidget(button)
layout.addWidget(button2)
layout.setAlignment(Qt.AlignTop)
self.setLayout(layout)
def submitSearch(self):
self.searchSubmitted.emit()
self.passQuery.emit(self.textbox.text())
And here is the results file:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Results(QWidget):
clicked = pyqtSignal()
def __init__(self, parent=None):
super(Results, self).__init__(parent)
# Create Logo
logo = QLabel(self)
pixmap = QPixmap('res/logo.png')
logo.setPixmap(pixmap)
logo.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
logo.setAlignment(Qt.AlignCenter)
# Create page contents
label = QLabel(text="This is the results page. If you see this, it's still broken.")
label.setAlignment(Qt.AlignCenter)
button = QPushButton(text='Add to watching.')
button2 = QPushButton(text='Go back.')
button2.clicked.connect(self.clicked.emit)
# Set up layout
layout = QVBoxLayout()
layout.addWidget(logo)
layout.addWidget(label)
layout.addWidget(button)
layout.addWidget(button2)
layout.setAlignment(Qt.AlignTop)
self.setLayout(layout)
#pyqtSlot(str)
def grabSearch(self, str):
print(str)
self.label.setText(str)
The way I understand it, what I have right now should be working. When the user submits some text on the search page, it calls the submitSearch() function. That function emits two signals: the first, searchSubmitted, changes the screen to the results screen (this works as intended). The second, passQuery, should be passing the contents of the textbox to the connected function grabSearch() in the results file. However, the passQuery never seems to be caught by the results page despite being connected. I've verified with print statements that it is being emitted, but that's it.
What am I missing here?
Your code has the following errors:
If you are going to use a lambda to make the connection you must invoke the function with the arguments.
self.searchScreen.passQuery.connect(lambda text: self.resultsScreen.grabSearch(text))
But it is better to use the direct connection since the signatures are the same:
self.searchScreen.passQuery.connect(self.resultsScreen.grabSearch)
Another error is that the results.py label must be a member of the class:
self.label = QLabel(text="This is the results page. If you see this, it's still broken.") # <--
self.label.setAlignment(Qt.AlignCenter) # <--
# ..
# Set up layout
layout = QVBoxLayout()
layout.addWidget(logo)
layout.addWidget(self.label) # <--
And finally do not use reserved words like str, change to:
#pyqtSlot(str)
def grabSearch(self, text):
self.label.setText(text)
I'm trying to update the value of a Traitsui variable to match a user-defined variable given via PyQt interface.
This seems like something so simple, but has taken me numerous hours now. The print functions I've used here show that the traits variable is updating, but the actual traits window is not refreshing to match.
import sys, os
from pyface.qt import QtGui, QtCore
os.environ['ETS_TOOLKIT'] = 'qt4'
from traits.api import HasTraits,Instance,on_trait_change,Int
from traitsui.api import View,Item,VGroup
class Traits_Scene(HasTraits):
traitsui_value = 0
def update_traitsui_value(self):
Traits_Scene.traitsui_value = P1.pyqt_value
print 'Traitsui value =',self.traitsui_value
view = View(
VGroup(
Item('traitsui_value',springy=False,show_label=True,style='readonly'),
),
resizable=True,
)
class P1(QtGui.QWidget):
pyqt_value = 0
print 'PyQt value =',pyqt_value
def __init__(self, parent=None):
super(P1, self).__init__(parent)
layout = QtGui.QGridLayout(self)
def set_value():
P1.pyqt_value = self.entry.value()
print 'PyQt value =',P1.pyqt_value
Traits_Scene().update_traitsui_value()
self.entry = QtGui.QSpinBox(self)
self.entry.setMinimum(0)
self.entry.setMaximum(10)
self.entry.setValue(0)
self.entry.setPrefix('PyQt value: ')
self.entry.valueChanged.connect(set_value)
layout.addWidget(self.entry, 0, 0, 1, 1)
self.entry.show()
self.viz1 = Traits_Scene()
self.ui1 = self.viz1.edit_traits(parent=self, kind='subpanel').control
layout.addWidget(self.ui1, 1, 0, 1, 1)
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.window = P1(self)
self.setCentralWidget(self.window)
self.show()
if __name__ == '__main__':
app = QtGui.QApplication.instance()
w = MainWindow()
sys.exit(app.exec_())
I'm creating a table widget that I want to auto-refresh at certain intervals. The trouble I'm having is that refreshing the contents of the table is resetting their rowHeight property and ignoring the call to setRowHeight().
For example, I have a repeater class here running on a separate thread:
class RepeatedTimer(QtCore.QThread):
def __init__(self, obj):
super(RepeatedTimer, self).__init__(obj)
self.obj = obj
self.stop = False
def run(self):
while not self.stop:
time.sleep(2)
self.obj.refresh()
and it's being used in my QTableWidget like this:
from PySide import QtCore, QtGui
import sys, time
class TestTable(QtGui.QTableWidget):
def __init__(self, parent=None):
super(TestTable, self).__init__(parent)
self.setColumnCount(1)
self.thread = RepeatedTimer(self) # Create the auto-refresher thread
self.thread.start() # Start the thread
self.refresh()
def refresh(self):
print "Clearing table"
while self.rowCount():
self.removeRow(0)
for each in xrange(3):
self.insertRow(each)
text = str(time.time())
item = QtGui.QTableWidgetItem(text)
self.setItem(each, 0, item)
for row in xrange(self.rowCount()):
self.setRowHeight(row, 100) # This part is not behaving as expected
print 'Row %d height: %d' % (row, self.rowHeight(row))
def closeEvent(self, event):
print 'Stopping thread...'
self.thread.stop = True
self.thread.exit()
app = QtGui.QApplication(sys.argv)
test = TestTable()
test.show()
sys.exit(app.exec_())
If you run this, you'll see that each time the table refreshes, it clears all the contents, adds new items in each row, and sets all the row heights to 100. Except that last part. It is correctly looping through the rows because it prints each time. But for some reason it stops setting the row heights after the first loop.
Any ideas why this is happening?
It is not necessary to create a thread to update the QTableWidget, you could use a QTimer, on the other hand remove QTableWidgetItem and set them again is expensive so I recommend you update them.
import sys
import time
from PySide import QtCore, QtGui
class TestTable(QtGui.QTableWidget):
def __init__(self, parent=None):
super(TestTable, self).__init__(parent)
self.setRowCount(3)
self.setColumnCount(1)
for row in range(self.rowCount()):
for col in range(self.columnCount()):
self.setItem(row, col, QtGui.QTableWidgetItem(str(time.time())))
for each in range(self.rowCount()):
self.setRowHeight(each, 100)
self.setColumnWidth(each, 250)
timer_refresh = QtCore.QTimer(self)
timer_refresh.timeout.connect(self.refresh)
timer_refresh.start(2000)
def refresh(self):
for row in range(self.rowCount()):
for col in range(self.columnCount()):
self.item(row, col).setText(str(time.time()))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
test = TestTable()
test.show()
sys.exit(app.exec_())
Sorry, but you do not need a separate thread for this task.
Use the QTimer class provides repetitive and single-shot timers.
Here is an example, sorry for me PyQt5
import sys
import time
#from PySide import QtCore, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class TestTable(QTableWidget):
def __init__(self, parent=None):
super(TestTable, self).__init__(parent)
self.setWindowTitle("QTableWidget setRowHeight ")
self.resize(530, 330);
self.setRowCount(3)
self.setColumnCount(1)
self.setHorizontalHeaderLabels(['time.time())',])
for each in range(3):
self.setRowHeight(each, 100)
self.setColumnWidth(each, 250)
self.my_qtimer = QTimer(self)
self.my_qtimer.timeout.connect(self.timerTick)
self.my_qtimer.start(1000) # msec
def timerTick(self):
for each in range(3):
item = QTableWidgetItem(str(time.time()))
self.setItem(0, each, item)
app = QApplication(sys.argv)
test = TestTable()
test.show()
sys.exit(app.exec_())