PyGTK TreeView showing blank rows from ListStore - python

I'm trying to show several rows from database in a TreeView but all I am getting are some dummy rows as you can see in the image below.
class SettingsDialog(gtk.Dialog):
def __init__(self):
gtk.Dialog.__init__(self, "Server Settings", self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
# Instantiate ServerManager
self.server_manager = ServerManager()
# Create TreeStore for Server list
self.liststore = gtk.ListStore(str, str)
self.treeview = gtk.TreeView(self.liststore)
# Create TreeViewColumns to display data
cell = gtk.CellRendererText()
col = gtk.TreeViewColumn("Name")
col.pack_start(cell, True)
self.treeview.append_column(col)
cell = gtk.CellRendererText()
col = gtk.TreeViewColumn("URL")
col.pack_start(cell, True)
self.treeview.append_column(col)
self.vbox.pack_start(self.treeview)
self.resize(500,350)
self.set_position(gtk.WIN_POS_CENTER)
self.show_all()
self.load_server_list()
def load_server_list(self):
self.liststore.clear()
servers = self.server_manager.list()
for name, url in servers.iteritems():
self.liststore.append([name, url])
self.show_all()
Data returned from self.server_manager.list() is valid an added to the list store perfectly. There seems to be something wrong with the CellRenderers but I wasn't able to find the error.

You have to set an attribute mapping on the column. For example, the cellrenderer's text attribute value will be displayed in the treeview cell. It is taken from the values on the data model (self.liststore). The column number on the model where the value is taken from is specified in the attribute mapping.
## Take value for *text* attribute of the cell renderer from the model's 3rd column
col = gtk.TreeViewColumn(title, cellrenderer, text=2)

Related

Pandas table customization

This is a section of my python code, this class retrieves a sheet from smartsheet and turns it into a df, which later uses to display on a table on my GUI. I've been trying to change row colors but cant seem to get it right, in the code I managed to change the color of columns, however when I pass self.table.rowcolors... it does nothing. Anyone has an idea of what else I could try?
class SmartsheetFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.configure(bg='white')
# Get the sheet
sheet_id = 3839061875025796
ss_client = smartsheet.Smartsheet(access_token=os.environ.get('SMARTSHEET_ACCESS_TOKEN'))
sheet = ss_client.Sheets.get_sheet(sheet_id)
rows = sheet.rows
columns = sheet.columns
#Creating a dataframe from the sheet
df = pd.DataFrame(columns=[col.title for col in columns])
for row in rows:
df.loc[row.id] = [col.value for col in row.cells]
last_4_rows = df.tail(4)
# Create a Table widget and set its properties
self.table = pt.Table(self, dataframe=df, showstatusbar=True, height=600, width=1200)
# Specify the row index you want to color
self.table.columncolors['AEM ID'] = 'forestgreen'
self.table.columncolors['Intel ID'] = 'midnightblue'
self.table.columncolors['Site'] = 'darkslategrey'
self.table.columncolors['Mode'] = 'firebrick'
self.table.redraw()
self.table.show()
I've tried many methods that I found online, so far I've managed to chage the color of columns, but havent been able to do the same for rows

How to expand row with text on click in Gtk.Treeview cell ? it's possible?

I have problem with trevieew, i need example to expand row by cell click on, similary to Gtk.Expander with arrow. Its that possible ? I put long string to column "Data", and i want show all / hide this text on click. I tried used Gtk.Expander, but this widget is incompatibility with gtk.TreeView.
example:
The trick to getting rows in a Gtk.TreeView to expand with an arrow similar to Gtk.Expander is to add some rows as 'top level' and some rows as 'children'. This relationship is managed using the Gtk.TreeIter objects that are returned by Gtk.TreeStore.append(). When this relationship is established, TreeView automatically adds arrows beside collapsible rows. For example:
def add_data(self, data):
""" Add data to the Gtk.TreeStore """
for key, value in data.items():
top_level_row = self.tree_store.append(None, [key, ""])
for item in value:
child_row = self.tree_store.append(top_level_row,[item[0], item[1]])
In this function, data is sent as a dictionary. The key is set as a top-level row by passing 'None' as the first value to the .append() function. This has the effect of setting the root node of the tree store as the parent for this row. The .append() function returns a Gtk.TreeIter object that points to this new row.
The key's value (a list of student values) is iterated over and each list item is set as a child of this row. This is accomplished by passing the Gtk.TreeIter of the parent row ('top_level_row') as the first parameter of the .append() function for each child of that row.
A ready-to-run example program:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
student_data = {'Grade 8': [
['Simpson, Lisa', 'F'],
['Bueller, Feris', 'M'],
['Standish, Claire', 'F']
],
'Grade 9': [
['Wiggum, Ralph', 'M'],
['Frye, Cameron', 'M'],
['Vernon, Richard', 'M']
]}
class TreeViewExample(Gtk.Window):
TREE_ROOT = None # Index value for the tree's root node
NAME = 0 # Column index for 'name' data
GENDER = 1 # Column index for 'gender' data
def __init__(self):
# Initialize window
Gtk.Window.__init__(self, title="TreeView")
self.set_size_request(300, 300)
self.set_position(Gtk.WindowPosition.CENTER)
self.tree_store = Gtk.TreeStore(str, str) # Create a Gtk.TreeStore to hold data
self.add_data(student_data) # Add data to the TreeStore
self.treeview = Gtk.TreeView(model=self.tree_store) # Create the Gtk.TreeView container
self.add(self.treeview) # Add the TreeView to the window
# CellRenderer for text
text_renderer = Gtk.CellRendererText()
# Create a TreeView column to hold student names
col_combined = Gtk.TreeViewColumn("Student")
col_combined.pack_start(text_renderer, False)
col_combined.add_attribute(text_renderer, "text", self.NAME)
self.treeview.append_column(col_combined)
# Create a TreeView column to hold student genders
col_combined = Gtk.TreeViewColumn("Gender")
col_combined.pack_start(text_renderer, False)
col_combined.add_attribute(text_renderer, "text", self.GENDER)
self.treeview.append_column(col_combined)
def add_data(self, data):
""" Add data to the Gtk.TreeStore """
for key, value in data.items():
top_level_row = self.tree_store.append(None, [key, ""])
for item in value:
child_row = self.tree_store.append(top_level_row,
[item[self.NAME],
item[self.GENDER]])
win = TreeViewExample()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
This program outputs the following result:

Check row by row in QTableWidget to affect QCombobox

I have a QTableWidget, 2 Columns in which the first column contains the name of items while the second column is populated with qcomboboxes (created using cellwidgets) which contains a list of color options (eg. "", RED, BLUE, GREEN)
For example, in the following table, items denoted with * has a variable called color_set, I am trying to achieve as follows:
it will lookup the names of items in the scene
then it will go through a function to check and see if the item
shirt_01 contains a variable called color_set
If the variable exists, say if it is RED, it will then lookup the list of options in the combobox and display RED as the value
If the variable does not exists, it will displays a blank field instead
this function/values populate the table with information before the ui is launched, it is not a button clicked function etc.
Name of items | Color Options
shirt_01* | RED
shirt_02 |
pants* | GREEN
However, instead of getting my ui to output as above, I got the following result:
Name of items | Color Options
shirt_01* | RED
shirt_02 | RED
pants* | GREEN
For some reasons, the shirt_02 seems to got 'tangled' and displayed the same result as shirt_01. And I think it could possibly be due to how my logic was written but I could not figure it out or because I keep tying my output result to self.color_combobox as my code initially checks through the first column then find the matching text in the second column.
But I keep getting error at the line - item_name has no attribute .text()
import maya.cmds as cmds
from PyQt4 import QtGui, QtCore
import json
def get_all_mesh():
all_mesh = cmds.listRelatives(cmds.ls(type = 'mesh'), parent=True)
return all_mesh
def read_json(node_name):
# checks if the node_name exists in the json file
with open('/Desktop/car_colors.json') as data_file:
data = json.load(data_file)
items = set()
for index, name in enumerate(data):
# if the name is in the json, it will states the color
if node_name in name:
for item in (data[name]):
#print "{0} - {1}".format(name, item)
items.add(item)
return items
def attrToPy(objAttr):
stringAttrData = str(cmds.getAttr(objAttr))
loadedData = cPickle.loads(stringAttrData)
return loadedData
class testTableView(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.setWindowTitle('Color Test')
self.setModal(False)
self.all_mesh = get_all_mesh()
# Build the GUI
self.init_ui()
self.populate_data()
def init_ui(self):
# Table setup
self.mesh_table = QtGui.QTableWidget()
self.mesh_table.setRowCount(len(self.all_mesh))
self.mesh_table.setColumnCount(3)
self.mesh_table.setHorizontalHeaderLabels(['Mesh Found', 'Color for Mesh'])
self.md_insert_color_btn = QtGui.QPushButton('Apply color')
# Layout
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.mesh_table)
self.layout.addWidget(self.md_insert_color_btn)
self.setLayout(self.layout)
def populate_data(self):
geo_name = self.all_mesh
for row_index, geo_item in enumerate(geo_name):
new_item = QtGui.QTableWidgetItem(geo_item)
# Add in each and every mesh found in scene and append them into rows
self.mesh_table.setItem(row_index, 0, new_item)
geo_exclude_num = ''.join(i for i in geo_item if not i.isdigit())
color_list = read_json(geo_exclude_num)
color_list.add("")
# Insert in the color
self.color_combobox = QtGui.QComboBox()
#color_list = get_color()
self.color_combobox.addItems(list(sorted(color_list)))
self.mesh_table.setCellWidget(row_index, 1, self.color_combobox)
self.color_value_to_combobox()
def color_value_to_combobox(self):
obj_nodes = get_all_mesh()
for node in obj_nodes:
# This attribute is stored in the Extra Attributes
objAttr = '%s.pyPickle'%node
storedData = attrToPy(objAttr)
if 'color_set' in storedData:
color_variant = storedData['color_set']
combo_index = self.color_combobox.findText(color_variant, QtCore.Qt.MatchFixedString)
self.color_combobox.setCurrentIndex(0 if combo_index < 0 else combo_index)
# To opent the dialog window
dialog = testTableView()
dialog.show()
Is there anyway in which I can make my ui to check for the list of item in scene, tallies which name and combobox it should go (in terms of which rows/columns)? Otherwise what other ways can i approach?
EDIT: This is the attachment that I did it quick - Link
If you run the UI, you will notice that pCube1 has the color "red" while pCube2 is "blue", however both the comboboxes will turn up as blue instead
Ok, so the problem was in color_value_to_combobox. Instead of setting the combobox for ALL objects, you need to specify what object and combobox the function needs to work on. The major flaw was that you were using self.color_combobox to set with every time, so every object would keep setting the same combobox! It needs to be more generic.
Anyways, I just had to change the end of populate_data and color_value_to_combobox. Now cube1 shows red, and cube2 shows blue.
import maya.cmds as cmds
from PyQt4 import QtGui, QtCore
import json
import cPickle
def get_all_mesh():
all_mesh = cmds.listRelatives(cmds.ls(type = 'mesh'), parent=True)
return all_mesh
def read_json(node_name):
# checks if the node_name exists in the json file
with open('/Desktop/car_colors.json') as data_file:
data = json.load(data_file)
items = set()
for index, name in enumerate(data):
# if the name is in the json, it will states the color
if node_name in name:
for item in (data[name]):
#print "{0} - {1}".format(name, item)
items.add(item)
return items
def attrToPy(objAttr):
stringAttrData = str(cmds.getAttr(objAttr))
loadedData = cPickle.loads(stringAttrData)
return loadedData
class testTableView(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.setWindowTitle('Color Test')
#self.setModal(False)
self.all_mesh = get_all_mesh()
# Build the GUI
self.init_ui()
self.populate_data()
def init_ui(self):
# Table setup
self.mesh_table = QtGui.QTableWidget()
self.mesh_table.setRowCount(len(self.all_mesh))
self.mesh_table.setColumnCount(3)
self.mesh_table.setHorizontalHeaderLabels(['Mesh Found', 'Color for Mesh'])
self.md_insert_color_btn = QtGui.QPushButton('Apply color')
# Layout
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.mesh_table)
self.layout.addWidget(self.md_insert_color_btn)
self.setLayout(self.layout)
def populate_data(self):
geo_name = self.all_mesh
for row_index, geo_item in enumerate(geo_name):
new_item = QtGui.QTableWidgetItem(geo_item)
# Add in each and every mesh found in scene and append them into rows
self.mesh_table.setItem(row_index, 0, new_item)
geo_exclude_num = ''.join(i for i in geo_item if not i.isdigit())
color_list = read_json(geo_exclude_num)
color_list.add("")
# Insert in the color
color_combobox = QtGui.QComboBox()
#color_list = get_color()
color_combobox.addItems(list(sorted(color_list)))
self.mesh_table.setCellWidget(row_index, 1, color_combobox)
self.color_value_to_combobox(geo_item, color_combobox) # Pass the object and combobox you want to set
# This use to work on all mesh objects, but only edits a single combobox. This is wrong!
def color_value_to_combobox(self, node, combobox):
# This attribute is stored in the Extra Attributes
objAttr = '%s.pyPickle'%node
storedData = attrToPy(objAttr)
if 'color_set' in storedData:
color_variant = storedData['color_set']
combo_index = combobox.findText(color_variant, QtCore.Qt.MatchFixedString)
combobox.setCurrentIndex(0 if combo_index < 0 else combo_index) # Needs to work on the proper combobox!
# To opent the dialog window
dialog = testTableView()
dialog.show()
If the color variable doesn't exist, your code needs to explicitly set the color combo to a blank item:
def populate_data(self):
geo_name = self.all_mesh
for row_index, geo_item in enumerate(geo_name):
new_item = QtGui.QTableWidgetItem(geo_item)
# Add in each and every mesh found in scene and append them into rows
self.mesh_table.setItem(row_index, 0, new_item)
geo_exclude_num = ''.join(i for i in geo_item if not i.isdigit())
color_list = read_json(geo_exclude_num)
color_list.add("")
# Insert in the color
color_combobox = QtGui.QComboBox()
#color_list = get_color()
color_combobox.addItems(list(sorted(color_list)))
self.mesh_table.setCellWidget(row_index, 1, color_combobox)
# This attribute is stored in the Extra Attributes
objAttr = '%s.pyPickle' % geo_item
storedData = attrToPy(objAttr)
if 'color_set' in storedData:
color_variant = storedData['color_set']
else:
color_variant = ''
combo_index = color_combobox.findText(color_variant, QtCore.Qt.MatchFixedString)
color_combobox.setCurrentIndex(0 if combo_index < 0 else combo_index)
(NB: for this to work, you obviously must make sure the first entry in the combo-boxes is a blank item).
If you look at the code you posted, it doesn't show the loop over the rows to put the combo boxes in each cell, but I will assume there is one otherwise it wouldn't work at all.
What you should do is one of two things:
- if you have a separate loop to create your combo boxes then in that loop don't create a combo box if the item does not have colors; then in the second loop you check if the cell has a combo box and only if it does do you configure it.
- Second option is to move the first loop into the rows loop, ie you as loop through each row you determine if the item has colors, and only if it does, do you create the combo box and configure it; if no colors, just leave that sell empty.

QTableview specify standard search field

I have a QTableView with the following code below. It runs fine, but when I am typing the search field is always the first column, which is the number and primary key.
How can I change that the standard search field is another field, second (name) for example, even with select column on the name column or with setsort on name the standard search when typing is the first number field?
When the code is running, I can change the search column by left-clicking in the second column, but I want to achieve this programmatically.
class KL_browse(QDialog, ui_kl_browse.Ui_kl_browse):
def __init__(self):
super(KL_browse, self).__init__()
query = QSqlQuery()
query.exec_("""SELECT * FROM klanten""")
self.setupUi(self)
self.model = QSqlTableModel(self)
self.model.setTable("klanten")
self.model.setSort(1, Qt.AscendingOrder)
self.model.select()
self.tableView.setModel(self.model)
self.tableView.setSelectionMode(QTableView.SingleSelection)
self.tableView.setSelectionBehavior(QTableView.SelectRows)
# self.view.setColumnHidden(ID, True)
self.tableView.horizontalHeader().setSectionsMovable(True)
self.tableView.horizontalHeader().setDragEnabled(True)
self.tableView.horizontalHeader().setDragDropMode(QAbstractItemView.InternalMove)
self.tableView.horizontalHeader().setSortIndicator(1,0)
self.tableView.selectRow(0)
self.tableView.selectColumn(1)
You need to change the index as follows:
# index: the index of a cell in the desired column
index = tableView.model().index(0, 1)
tableView.selectionModel().setCurrentIndex(index, QItemSelectionModel.NoUpdate);

How to make GtkListStore store object attribute in a row?

I'w trying to keep at ListStore non-text objects using snippet I found. These are the objects:
class Series(gobject.GObject, object):
def __init__(self, title):
super(Series, self).__init__()
self.title = title
gobject.type_register(Series)
class SeriesListStore(gtk.ListStore):
def __init__(self):
super(SeriesListStore, self).__init__(Series)
self._col_types = [Series]
def get_n_columns(self):
return len(self._col_types)
def get_column_type(self, index):
return self._col_types[index]
def get_value(self, iter, column):
obj = gtk.ListStore.get_value(self, iter, 0)
return obj
And now I'm trying to make TreeView display it:
...
liststore = SeriesListStore()
liststore.clear()
for title in full_conf['featuring']:
series = Series(title)
liststore.append([series])
def get_series_title(column, cell, model, iter):
cell.set_property('text', liststore.get_value(iter, column).title)
return
selected = builder.get_object("trvMain")
selected.set_model(liststore)
col = gtk.TreeViewColumn(_("Series title"))
cell = gtk.CellRendererText()
col.set_cell_data_func(cell, get_series_title)
col.pack_start(cell)
col.add_attribute(cell, "text", 0)
selected.append_column(col)
...
But it fails with errors:
GtkWarning:
gtk_tree_view_column_cell_layout_set_cell_data_func:
assertion info != NULL' failed
col.set_cell_data_func(cell,
get_series_title)
Warning: unable to set propertytext'
of type gchararray' from value of
typedata+TrayIcon+Series'
window.show_all()
Warning: unable to set property text'
of typegchararray' from value of
type `data+TrayIcon+Series'
gtk.main()gtk.main()
What should I do to make it work?
Two mistakes in the second-to-last block.
GtkWarning: gtk_tree_view_column_cell_layout_set_cell_data_func: assertion `info != NULL'
In English, this means that the cell renderer is not in the column's list of cell renderers. You need to add the cell renderer to the column first before calling set_cell_data_func.
Warning: unable to set property `text' of type `gchararray' from value of `typedata+TrayIcon+Series'
This is because the add_attribute line causes GTK+ to try setting the cell text to a Series object, which of course fails. Just remove that line; the cell data func already takes care of setting the cell text.
In code:
col = gtk.TreeViewColumn(_("Series title"))
cell = gtk.CellRendererText()
col.pack_start(cell)
col.set_cell_data_func(cell, get_series_title)

Categories