Passing changing data from tab to tab - python

I am trying to build a program with two tabs. In Tab1 I select point coordinates (x,y) from an image into values self.a. Besides the image I also have some other UI in Tab1 (i.e. a table). Now, I want to pass the values self.a to Tab2 (without inheriting all the other stuff). Keep in mind that self.a can be constantly updated when a new point is clicked.
from PySide import QtGui, QtCore
import pandas as pd
import pyqtgraph as pg
import numpy as np
QVariant = lambda value=None: value
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
v_global_layout = QtGui.QVBoxLayout()
v_global_layout.addWidget(TabDialog())
v_global_layout.setAlignment(QtCore.Qt.AlignTop)
self.setLayout(v_global_layout)
class TabDialog(QtGui.QDialog):
def __init__(self, parent=None):
super().__init__(parent)
tab_widget = QtGui.QTabWidget()
tab_widget.addTab(Tab1(), "1")
tab_widget.addTab(Tab2(), "2")
main_layout = QtGui.QVBoxLayout()
main_layout.addWidget(tab_widget)
self.setLayout(main_layout)
class Tab1(QtGui.QTabWidget):
def __init__(self):
super().__init__()
layout = QtGui.QHBoxLayout()
self.fig = pg.PlotWidget(name='Example: Selecting scatter points')
self.plot_area = self.fig.plotItem
self.a = pg.ScatterPlotItem(pxMode=False)
spots = []
for i in range(10):
for j in range(10):
spots.append({'pos': (1*i, 1*j), 'size': 1, 'pen': {'color': 'w', 'width': 2},
'brush': pg.intColor(i*10+j, 100)})
self.a.addPoints(spots)
self.plot_area.addItem(self.a)
self.a.dataModel = DataFrameModel()
self.a.dataTable = QtGui.QTableView()
self.a.dataTable.setModel(self.a.dataModel)
layout.addWidget(self.a.dataTable)
layout.addWidget(self.fig)
self.setLayout(layout)
self.a.array = np.zeros((0, 2))
def clicked(self, points):
for p in points:
p.setPen('b', width=2)
position = p.viewPos()
self.array = np.append(self.array, np.array([[position.x(), position.y()]]), axis=0)
c = range(len(self.array))
c = list(map(str, c))
self.dataModel.signalUpdate(self.array, columns=c)
self.dataModel.printValues() # also: print(self.array)
self.a.sigClicked.connect(clicked)
class Tab2(QtGui.QTabWidget):
def __init__(self):
super().__init__()
layout = QtGui.QHBoxLayout()
##### Here I want to use Tab1.a and not inherit all the other stuff(layout) #####
#print("values = ", Tab1.a.array) # a should change when a new point is selected in Tab1
#####################################
self.setLayout(layout)
class DataFrameModel(QtCore.QAbstractTableModel):
""" data model for a DataFrame class """
def __init__(self):
super(DataFrameModel, self).__init__()
self.df = pd.DataFrame()
def signalUpdate(self, dataIn, columns):
self.df = pd.DataFrame(dataIn, columns)
self.layoutChanged.emit()
def printValues(self):
print("DataFrame values:\n", self.df.values)
def values(self):
return self.df.values
#------------- table display functions -----------------
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QVariant()
if orientation == QtCore.Qt.Horizontal:
try:
return self.df.columns.tolist()[section]
except (IndexError, ):
return QVariant()
elif orientation == QtCore.Qt.Vertical:
try:
# return self.df.index.tolist()
return self.df.index.tolist()[section]
except (IndexError, ):
return QVariant()
def data(self, index, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QVariant()
if not index.isValid():
return QVariant()
return QVariant(str(self.df.ix[index.row(), index.column()]))
def rowCount(self, index=QtCore.QModelIndex()):
return self.df.shape[0]
def columnCount(self, index=QtCore.QModelIndex()):
return self.df.shape[1]
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
main_window = Widget()
main_window.setGeometry(100, 100, 640, 480)
main_window.show()
sys.exit(app.exec_())

In this case, you can just use signals to get the job done.
Here you are trying to access Tab1.a like a static property, when it is not one. Ideally, we should try and decouple the different widgets. We should try and keep the dependency between them to a minimum and treat each of them as ignorant and unaware of each other. The TabDialog can be the one that knows about each of these widgets and the connections between them (In this case, Tab1 and Tab2). And hence, the TabDialog can take the responsibility of communication between these widgets.
To do this, we have the two tabs as properties of the TabDialog class like so:
# Have the tabs as this dialog's class properties
self.tab1 = Tab1(image)
self.tab2 = Tab2()
tab_widget.addTab(self.tab1, "1")
tab_widget.addTab(self.tab2, "2")
In the class Tab2, let us assume that the value you want to map with Tab1.a is points_from_tab1_a:
class Tab2(QtGui.QTabWidget):
def __init__(self):
super().__init__()
layout = QtGui.QHBoxLayout()
self.points_from_tab1_a = []
self.setLayout(layout)
Now, in TabDialog, we connect the sigClicked signal of tab1.a to a method that updates tab2.points_from_tab1_a:
self.tab1.a.sigClicked.connect(self.pointChanged)
def pointChanged(self, points):
tab2.points_from_tab1_a = tab1.a
And that should do the trick. So, your full code snippet, after these changes, would look like:
from PySide import QtGui, QtCore
import pandas as pd
import pyqtgraph as pg
import numpy as np
QVariant = lambda value=None: value
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
v_global_layout = QtGui.QVBoxLayout()
v_global_layout.addWidget(TabDialog())
v_global_layout.setAlignment(QtCore.Qt.AlignTop)
self.setLayout(v_global_layout)
class TabDialog(QtGui.QDialog):
def __init__(self, parent=None):
super().__init__(parent)
tab_widget = QtGui.QTabWidget()
# Have the tabs as this dialog's class properties
self.tab1 = Tab1(image)
self.tab2 = Tab2()
tab_widget.addTab(self.tab1, "1")
tab_widget.addTab(self.tab2, "2")
self.tab1.a.sigClicked.connect(self.pointChanged)
main_layout = QtGui.QVBoxLayout()
main_layout.addWidget(tab_widget)
self.setLayout(main_layout)
def pointChanged(self, points):
tab2.points_from_tab1_a = tab1.a
class Tab1(QtGui.QTabWidget):
def __init__(self):
super().__init__()
layout = QtGui.QHBoxLayout()
self.fig = pg.PlotWidget(name='Example: Selecting scatter points')
self.plot_area = self.fig.plotItem
self.a = pg.ScatterPlotItem(pxMode=False)
spots = []
for i in range(10):
for j in range(10):
spots.append({'pos': (1*i, 1*j), 'size': 1, 'pen': {'color': 'w', 'width': 2},
'brush': pg.intColor(i*10+j, 100)})
self.a.addPoints(spots)
self.plot_area.addItem(self.a)
self.a.dataModel = DataFrameModel()
self.a.dataTable = QtGui.QTableView()
self.a.dataTable.setModel(self.a.dataModel)
layout.addWidget(self.a.dataTable)
layout.addWidget(self.fig)
self.setLayout(layout)
self.a.array = np.zeros((0, 2))
def clicked(self, points):
for p in points:
p.setPen('b', width=2)
position = p.viewPos()
self.array = np.append(self.array, np.array([[position.x(), position.y()]]), axis=0)
c = range(len(self.array))
c = list(map(str, c))
self.dataModel.signalUpdate(self.array, columns=c)
self.dataModel.printValues() # also: print(self.array)
self.a.sigClicked.connect(clicked)
class Tab2(QtGui.QTabWidget):
def __init__(self):
super().__init__()
layout = QtGui.QHBoxLayout()
self.points_from_tab1_a = []
##### Here I want to use Tab1.a and not inherit all the other stuff(layout) #####
#print("values = ", Tab1.a.array) # a should change when a new point is selected in Tab1
#####################################
self.setLayout(layout)
class DataFrameModel(QtCore.QAbstractTableModel):
""" data model for a DataFrame class """
def __init__(self):
super(DataFrameModel, self).__init__()
self.df = pd.DataFrame()
def signalUpdate(self, dataIn, columns):
self.df = pd.DataFrame(dataIn, columns)
self.layoutChanged.emit()
def printValues(self):
print("DataFrame values:\n", self.df.values)
def values(self):
return self.df.values
#------------- table display functions -----------------
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QVariant()
if orientation == QtCore.Qt.Horizontal:
try:
return self.df.columns.tolist()[section]
except (IndexError, ):
return QVariant()
elif orientation == QtCore.Qt.Vertical:
try:
# return self.df.index.tolist()
return self.df.index.tolist()[section]
except (IndexError, ):
return QVariant()
def data(self, index, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QVariant()
if not index.isValid():
return QVariant()
return QVariant(str(self.df.ix[index.row(), index.column()]))
def rowCount(self, index=QtCore.QModelIndex()):
return self.df.shape[0]
def columnCount(self, index=QtCore.QModelIndex()):
return self.df.shape[1]
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
main_window = Widget()
main_window.setGeometry(100, 100, 640, 480)
main_window.show()
sys.exit(app.exec_())
Feel free to change it to suit your needs, using the signals and slots concept. Hope this was useful.

Related

How to implement a filterable List in PyQt5/PySide2?

How can I implement a simple filterable List in PyQt5/PySide2?
Test code:
import sys
from PySide2.QtCore import QAbstractListModel
from PySide2.QtGui import Qt
from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QListView
class MyModel(QAbstractListModel):
def __init__(self):
QAbstractListModel.__init__(self)
self.test_data = ['Test','abc', 'Test2', 'aaa', 'bbb']
self.filtered_data = self.test_data
self.filter = ''
self.refresh()
def refresh(self):
if self.filter:
self.filtered_data = [x for x in self.test_data if self.filter in x]
else:
self.filtered_data = self.test_data
def data(self, index, role):
if role == Qt.DisplayRole:
return self.filtered_data[index.row()]
def rowCount(self, index):
return len(self.filtered_data)
def text_changed():
model.filter = le.text()
model.refresh()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QWidget()
le = QLineEdit()
le.textChanged.connect(text_changed)
model = MyModel()
lv = QListView(model=model)
layout = QVBoxLayout()
layout.addWidget(le)
layout.addWidget(lv)
window.setLayout(layout)
window.show()
app.exec_()
The Filter itself works, but the ListView is not refreshed properly. When I change the filter, the list is not updated, until I move with the mouse to a entry.
That you change the information of an internal list does not notify in sight that something has changed, for each type of change certain methods must be invoked before or after the change.
In this case, beginResetModel and endResetModel are enough
def refresh(self):
self.beginResetModel()
if self.filter:
self.filtered_data = [x for x in self.test_data if self.filter in x]
else:
self.filtered_data = self.test_data
self.endResetModel()
Instead another more elegant solution is to use a QSortFilterProxyModel:
class MyModel(QAbstractListModel):
def __init__(self):
QAbstractListModel.__init__(self)
self.test_data = ['Test','abc', 'Test2', 'aaa', 'bbb']
self.filtered_data = self.test_data
def data(self, index, role):
if role == Qt.DisplayRole:
return self.filtered_data[index.row()]
def rowCount(self, index):
return len(self.filtered_data)
def text_changed():
proxy.filter = le.text()
class SortFilterProxyModel(QSortFilterProxyModel):
def __init__(self, parent=None):
super().__init__(parent)
self._filter = ""
def filterAcceptsRow(self, sourceRow, sourceParent):
index = self.sourceModel().index(sourceRow, 0, sourceParent)
if self.filter:
return self.filter in index.data()
return True
#property
def filter(self):
return self._filter
#filter.setter
def filter(self, f):
self._filter = f
self.invalidateFilter()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QWidget()
le = QLineEdit()
le.textChanged.connect(text_changed)
model = MyModel()
proxy = SortFilterProxyModel()
proxy.setSourceModel(model)
lv = QListView(model=proxy)
layout = QVBoxLayout()
layout.addWidget(le)
layout.addWidget(lv)
window.setLayout(layout)
window.show()
app.exec_()

Refreshing QTableView after loading new data

I'm trying to update a table/table model after loading a new csv so it shows the new values. Would updating the widget also some how manage this? I've cut down the code quite a bit below. You can use any 2 column csv:
0, 0, 0, 0, 0, 0,
import pandas as pd
from PySide2 import QtWidgets, QtGui, QtCore
def read_data(fname):
df = pd.read_csv(fname, sep=',', usecols=(0, 1), header=None)
df = df.dropna(how='any')
df = df[pd.to_numeric(df[0], errors='coerce').notnull()]
data_arr = df.to_numpy(dtype='float64')
return data_arr
class CustomTableModel(QtCore.QAbstractTableModel):
def __init__(self, data=None):
QtCore.QAbstractTableModel.__init__(self)
self.load_data(data)
def load_data(self, data):
self.input_x = data[:, 0]
self.input_y = data[:, 1]
self.column_count = 2
self.row_count = len(self.input_x)
def rowCount(self, parent=QtCore.QModelIndex()):
return self.row_count
def columnCount(self, parent=QtCore.QModelIndex()):
return self.column_count
def headerData(self, section, orientation, role):
if role != QtCore.Qt.DisplayRole:
return None
if orientation == QtCore.Qt.Horizontal:
return ("x", "y")[section]
else:
return "{}".format(section)
def data(self, index, role=QtCore.Qt.DisplayRole):
column = index.column()
row = index.row()
if role == QtCore.Qt.DisplayRole:
if column == 0:
return str(self.input_x[row])
elif column == 1:
return str(self.input_y[row])
elif role == QtCore.Qt.BackgroundRole:
return QtGui.QColor(QtCore.Qt.white)
elif role == QtCore.Qt.TextAlignmentRole:
return QtCore.Qt.AlignRight
return None
class Widget(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
try:
self.data
except AttributeError:
self.open_csv()
self.model = CustomTableModel(self.data)
self.table_view = QtWidgets.QTableView()
self.table_view.setModel(self.model)
resize = QtWidgets.QHeaderView.ResizeToContents
self.horizontal_header = self.table_view.horizontalHeader()
self.vertical_header = self.table_view.verticalHeader()
self.horizontal_header.setSectionResizeMode(resize)
self.vertical_header.setSectionResizeMode(resize)
self.horizontal_header.setStretchLastSection(False)
# Creating layout
self.main_layout = QtWidgets.QVBoxLayout()
self.file_button = QtWidgets.QPushButton('CSV Import', self)
self.file_button.clicked.connect(self.open_csv)
self.main_layout.addWidget(self.table_view)
self.main_layout.addWidget(self.file_button)
self.setLayout(self.main_layout)
def open_csv(self):
filename, *_ = QtWidgets.QFileDialog.getOpenFileName(self, self.tr('Open CSV'),
self.tr("~/Desktop/"), self.tr('Files (*.csv)'))
self.data = read_data(filename)
return None
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, widget):
QtWidgets.QMainWindow.__init__(self)
self.setWindowTitle('Linear Plotter')
self.setCentralWidget(widget)
self.menu = self.menuBar()
self.file_menu = self.menu.addMenu('File')
exit_action = QtWidgets.QAction('Exit', self)
exit_action.setShortcut(QtGui.QKeySequence.Quit)
exit_action.triggered.connect(self.close)
self.file_menu.addAction(exit_action)
self.status = self.statusBar()
self.status.showMessage('Data loaded and plotted')
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
widget = Widget()
window = MainWindow(widget)
window.show()
sys.exit(app.exec_())
Not sure if QWidget.update() would work? I could not get it working.

Why does this pyside code not update its widget/view?

I am new to pyside and probably do not understand quite well the concepts of the GUI libraries. I have a specific question to the following code (python3.3), in which I create a view of a table, and a button. Once the button is pressed, data is added to the date of the widget, and the table should be redrawn. But the table does not update itself with the added contents.
How can I fix the code so the table updates/redraws itself after I press the 'Do_something' button?
For additional suggestions on my code I would be very thankful!
from PySide.QtCore import *
from PySide.QtGui import *
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
# this list represents the database
self.data_list = [
('John', 'Connor', 'terminated'),
('Buzz', 'Lightyea', 'animated')
]
self.header = ['name', 'lastname', 'extra']
# set basic window stuff
self.setGeometry(300, 200, 970, 450)
self.setWindowTitle("Main Stock Overview")
# add the model to the view
self.table_model = MyTableModel(self, self.data_list, self.header)
self.table_view = QTableView()
self.table_view.setModel(self.table_model)
# add the table to the layout
layout = QVBoxLayout(self)
layout.addWidget(self.table_view)
btn1 = QPushButton("Do_something", self)
btn1.clicked.connect(self.do_something)
# add some button to the layout
action_layout = QHBoxLayout(self)
action_layout.addStretch(1)
action_layout.addWidget(btn1)
layout.addLayout(action_layout)
self.setLayout(layout)
def do_something(self):
# update the 'database'
self.data_list.append(('Harry','Potter','wizated'))
print("data has been updated: ", self.data_list)
# required to be redrawn here
index1 = self.table_model.createIndex(0,0)
index2 = self.table_model.createIndex(self.table_model.rowCount(self)+1, self.table_model.columnCount(self))
self.table_model.dataChanged.emit(index1, index2)
class MyTableModel(QAbstractTableModel):
def __init__(self, parent, mylist, header, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.mylist = mylist
self.header = header
def rowCount(self, parent):
return len(self.mylist)
def columnCount(self, parent):
return len(self.mylist[0])
def data(self, index, role):
if not index.isValid():
return None
elif role != Qt.DisplayRole:
return None
return self.mylist[index.row()][index.column()]
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.header[col]
return None
app = QApplication([])
win = MyWindow()
win.show()
app.exec_()
After reading the docs a bit more it turns out that after adding new data row you need to emit the rowsInserted signal. So, the following is sufficient:
def do_something(self):
self.data_list.append(('Harry','Potter','wizated'))
newRow = len(self.data_list) - 1
self.table_model.rowsInserted.emit(QModelIndex(), newRow, newRow)

Setting background for row in PySide QTreeWidget

I started with the answer from a previous post but it doesn't seem to be working. All the rows render the same color.
I create a main window class
import sys
from PySide import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.settingsTree = SettingsTree()
self.setCentralWidget(self.settingsTree)
self.locationDialog = None
# self.autoRefreshAct.setChecked(True)
# self.fallbacksAct.setChecked(True)
self.setWindowTitle("Test")
self.resize(500, 600)
self.setTreeDataObject(ItemManifest())
self.settingsTree.setItemDelegate(SelectionColorDelegate(self.settingsTree))
def setTreeDataObject(self, treeData):
self.settingsTree.setTreeDataObject(treeData)
# self.refreshAct.setEnabled(True)
# self.autoRefreshAct.setEnabled(True)
The ItemManifest is used to hold data specific to list items (not really sure this is the Qt way of doing things)
class ItemManifest(QtCore.QObject):
def __init__(self, parent=None):
super(ItemManifest, self).__init__(parent)
self.myList = [{'name': 'a', 'vid':'1', 'pid': '1'},
{'name': 'b', 'vid':'2', 'pid': '1'},
{'name': 'c', 'vid':'3', 'pid': '1'}]
This is my actual tree widget with three columns:
class SettingsTree(QtGui.QTreeWidget):
def __init__(self, parent=None):
super(SettingsTree, self).__init__(parent)
self.setHeaderLabels(("Name", "vid", "pid"))
self.header().setResizeMode(0, QtGui.QHeaderView.Stretch)
self.header().setResizeMode(2, QtGui.QHeaderView.Stretch)
self.refreshTimer = QtCore.QTimer()
self.refreshTimer.setInterval(2000)
self.autoRefresh = False
self.groupIcon = QtGui.QIcon()
self.groupIcon.addPixmap(self.style().standardPixmap(QtGui.QStyle.SP_DirClosedIcon),
QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.groupIcon.addPixmap(self.style().standardPixmap(QtGui.QStyle.SP_DirOpenIcon),
QtGui.QIcon.Normal, QtGui.QIcon.On)
self.keyIcon = QtGui.QIcon()
self.keyIcon.addPixmap(self.style().standardPixmap(QtGui.QStyle.SP_FileIcon))
self.refreshTimer.timeout.connect(self.refresh)
def setTreeDataObject(self, treeData):
self.treeData = treeData
self.clear()
if self.treeData is not None:
self.treeData.setParent(self)
self.refresh()
if self.autoRefresh:
self.refreshTimer.start()
else:
self.refreshTimer.stop()
def sizeHint(self):
return QtCore.QSize(800, 600)
def setAutoRefresh(self, autoRefresh):
self.autoRefresh = autoRefresh
if self.treeData is not None:
if self.autoRefresh:
self.refresh()
self.refreshTimer.start()
else:
self.refreshTimer.stop()
def refresh(self):
if self.treeData is None:
return
# The signal might not be connected.
# try:
# self.itemChanged.disconnect(self.updateSetting)
# except:
# pass
self.updateChildItems(None)
# self.itemChanged.connect(self.updateSetting)
def event(self, event):
if event.type() == QtCore.QEvent.WindowActivate:
if self.isActiveWindow() and self.autoRefresh:
self.refresh()
return super(SettingsTree, self).event(event)
'''on change to settings update tree'''
def updateChildItems(self, parent):
dividerIndex = 0
for printer in self.treeData.myList:
childIndex = self.findChild(parent, printer['name'], 0)
if childIndex == -1 or childIndex >= dividerIndex:
if childIndex != -1:
child = self.childAt(parent, childIndex)
for i in range(child.childCount()):
self.deleteItem(child, i)
self.moveItemForward(parent, childIndex, dividerIndex)
else:
child = self.createItem(printer['name'], parent, dividerIndex)
child.setIcon(0, self.keyIcon)
dividerIndex += 1
else:
child = self.childAt(parent, childIndex)
child.setText(1, printer['vid'])
child.setText(2, printer['pid'])
def createItem(self, text, parent, index):
after = None
if index != 0:
after = self.childAt(parent, index - 1)
if parent is not None:
item = QtGui.QTreeWidgetItem(parent, after)
else:
item = QtGui.QTreeWidgetItem(self, after)
item.setText(0, text)
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
return item
def deleteItem(self, parent, index):
if parent is not None:
item = parent.takeChild(index)
else:
item = self.takeTopLevelItem(index)
del item
def childAt(self, parent, index):
if parent is not None:
return parent.child(index)
else:
return self.topLevelItem(index)
def childCount(self, parent):
if parent is not None:
return parent.childCount()
else:
return self.topLevelItemCount()
def findChild(self, parent, text, startIndex):
for i in range(self.childCount(parent)):
if self.childAt(parent, i).text(0) == text:
return i
return -1
def moveItemForward(self, parent, oldIndex, newIndex):
for int in range(oldIndex - newIndex):
self.deleteItem(parent, newIndex)
Create a color delegate for setting the background color of a row with text 'a' to green
class SelectionColorDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent):
super(SelectionColorDelegate, self).__init__(parent)
def initStyleOption(self, option, index):
# let the base class initStyleOption fill option with the default values
super(SelectionColorDelegate,self).initStyleOption(option, index)
# override what you need to change in option
if index.data() == 'a':
backColor = QtGui.QColor("green")
option.palette.setColor(QtGui.QPalette.Base, backColor)
option.backgroundBrush = backColor
make it work:
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())
Neither of my attempts at setting background color appear to be working.
After learning further on Qt I refactored the code to use the model/view relationship. The model is inherited from QtCore.QAbstractItemModel and implements the data method as follows:
class MyTreeModel(QtCore.QAbstractItemModel):
def data(self, index, role):
if not index.isValid():
return None
item = index.internalPointer()
if role == QtCore.Qt.BackgroundRole:
if item.status.status == 'Not installed':
return QtGui.QBrush(QtCore.Qt.lightGray)
if item.status.head_test_failed:
return QtGui.QBrush(QtCore.Qt.red)
if item.status.status == 'failure':
return QtGui.QBrush(QtCore.Qt.red)
if item.status.status == 'running':
return QtGui.QBrush(QtCore.Qt.green)
return QtGui.QBrush(QtCore.Qt.transparent)
if role != QtCore.Qt.DisplayRole:
return None
return item.data(index.column())
This way I was able to use to standard TreeView (or any other view for that matter). The role == QtCore.Qt.BackgroundRole tells the model that this is a formatting request.

Make checkbox by QAbstractTableModel

I want to make the first column with checkbox, and get the check status of that, how can I do that? I override the flag(), but it seems do not work, I am sure where is the problem?
And I got this links, but it does work for my code either. And I don't want to use delegate, because it is too complicated.
data = [['00','01','02'],
['10','11','12'],
['20','21','22']]
class MainWindow(QWidget):
def __init__(self, parent=None, *args):
super(MainWindow, self).__init__(parent)
clipTableWidget = QTableWidget()
self.model = TModel(data, self)
clipTableView = QTableView()
clipTableView.setModel(self.model)
layout = QVBoxLayout()
layout.addWidget(clipTableView)
self.setLayout(layout)
class TModel(QAbstractTableModel):
def __init__(self, datain, parent=None):
super(TModel, self).__init__(parent)
self.arraydata = datain
def rowCount(self, parent=QModelIndex()):
return len(self.arraydata)
def columnCount(self, parent=QModelIndex()):
return len(self.arraydata[0])
def data(self, index, role):
if not index.isValid():
return QVariant()
elif role != Qt.DisplayRole:
return QVariant()
return QVariant(self.arraydata[index.row()][index.column()])
def flags(self, index):
if not index.isValid():
return QVariant()
elif index.column() == 1:
return Qt.ItemIsSelectable|Qt.ItemIsEnabled|Qt.ItemIsUserCheckable
return QVariant()
Ok here is the solution to your problem. The reason Why your flags weren't working is because those flags dont work on text , they are meant for QItems .
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
class MainWindow(QWidget):
def __init__(self, parent=None, *args):
super(MainWindow, self).__init__(parent)
data = [['00','01','02'],
['10','11','12'],
['20','21','22']]
clipTableWidget = QTableWidget()
self.model = QStandardItemModel(self)
clipTableView = QTableView()
count1=0
for row in data:
count2 = 0
for column in row:
if count2 == 0:
item = QStandardItem(column)
item.setCheckable(True)
item.setCheckState(False)
item.setFlags(Qt.ItemIsUserCheckable| Qt.ItemIsEnabled)
self.model.setItem(count1,count2,item)
count2+=1
else:
item = QStandardItem(column)
self.model.setItem(count1,count2,item)
count2+=1
count1+=1
clipTableView.setModel(self.model)
layout = QVBoxLayout()
layout.addWidget(clipTableView)
self.setLayout(layout)
def main():
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Categories

Resources