GTKmm - How to put a pixbuf in a treeview - c++

I'm learning how to use GTKmm and I'm having a really hard time figuring out how to put an image into a treeview. I used Glade to create a treestore with 3 columns, one of which is a GdkPixbuf called store_pixbuf. I also created a treeview in glade, with a column that has both a pixbuf cell renderer called int_col_pict and a char array cell renderer. In my code, I have the usual MyColumns definition for the treestore like:
class MyModelColumns : public Gtk::TreeModel::ColumnRecord
{
public:
Gtk::TreeModelColumn<Glib::ustring> store_hostname;
Gtk::TreeModelColumn<Glib::ustring> store_intname;
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > store_pict;
MyModelColumns () { add(store_hostname); add(store_intname); add(store_pict);}
};
and use the following bit of code to populate it.
//Get a pointer to the treestore
Glib::RefPtr<Gtk::TreeStore> treestore = Glib::RefPtr<Gtk::TreeStore>::cast_static(builder->get_object("routerTreeStore"));
//make sure the pointer isn't bad
if(treestore){
MyModelColumns columns;
//populate the first column
Gtk::TreeRow row= *(treestore->append());
row[columns.store_hostname] = router->hostname;
//populate all children
for(int i=0; i<router->interfaces.size(); i++)
{
//append child row
Gtk::TreeRow child = *(treestore->append(row.children()));
//insert data into the row
child[columns.store_pict] = Gdk::Pixbuf::create_from_file("red_dot.png");
child[columns.store_intname] = router->interfaces[i].interfaceName;
}
}//if
I initially tried to use a stock image, but I could not figure out what function I was supposed to use, so then I tried to use Gdk::Pixbuf::create_from_file() (as you can see above), but at run time I get the following error:
Gtk-WARNING **: gtktreestore.c:765: Unable to convert from GdkPixbuf to gtkmm__GdkPixbuf
Click here to see what it looks like running. The image is supposed to go on the same line as the "FastEthernet..." lines
Does anyone know how I can solve this? Am I going about it completely wrong? Thanks for looking, every little bit of help is appreciated!

Your code looks correct. I just coded up a quick example and with gtkmm-2.4, I have no problems creating a column for a Glib::RefPtr
I couple of questions: what version of gtkmm are you using? Are you adding a column in the treeview for the Pixbuf?
I won't post my complete example but the relevant bits are:
in example.h
//Tree model columns:
class ModelColumns : public Gtk::TreeModel::ColumnRecord
{
public:
ModelColumns()
{ add(m_col_store_pict);}
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > m_col_store_pict;
};
ModelColumns m_Columns;
in example.cpp
//Create the Tree model:
m_refTreeModel = Gtk::ListStore::create(m_Columns);
m_TreeView.set_model(m_refTreeModel);
//Fill the TreeView's model
Gtk::TreeModel::Row row = *(m_refTreeModel->append());
row[m_Columns.m_col_store_pict] = Gdk::Pixbuf::create_from_file("/usr/share/icons/gnome/22x22/apps/arts.png");
row = *(m_refTreeModel->append());
row[m_Columns.m_col_store_pict] = Gdk::Pixbuf::create_from_file("/usr/share/icons/gnome/22x22/apps/fonts.png");
row = *(m_refTreeModel->append());
row[m_Columns.m_col_store_pict] = Gdk::Pixbuf::create_from_file("/usr/share/icons/gnome/22x22/apps/access.png");
//Add the TreeView's view columns:
m_TreeView.append_column("Some Picture", m_Columns.m_col_store_pict);
Is that any help?

If all you want is a potentially different stock icon for each row, you can do it by setting an pixbuf renderer attribute. The idea is that the column contains a string stock-id, which the renderer displays as an icon.
// in your class declaration
struct columnsRecord : public Gtk::TreeModel::ColumnRecord {
...
Gtk::TreeModelColumn<std::string> stockID; // stock id name
...
} treeColumns;
Gtk::CellRendererPixBuf pixBufRenderer;
...
// setting up columns
int numcols = treeView.append_column("Icon Column", pixBufRenderer); // returns # cols after append
treeView.get_column(numcols-1)->add_attribute(pixBufRenderer,"stock-id",treeColumns.stockID)
...
// setting a row
std::string id = good_val ? Gtk::Stock::YES.id : Gtk::Stock::NO.id;
rowiter->set_value(columns.stockID,id);

Looks like it's necessary to explicitly set CellRenderer for pixbuf cells.
This code snippet displays CANCEL icon on each data row.
Gtk::CellRendererPixbuf *cross = Gtk::manage(new Gtk::CellRendererPixbuf());
cross->property_stock_id() = Gtk::StockID(Gtk::Stock::CANCEL).get_string();
cross->property_stock_size() = Gtk::ICON_SIZE_BUTTON;
[...]
int cols_count = m_TreeView.append_column("icons", *cross);
For displaying custom images you need to remove two lines setting stock_id add something like this below:
Gtk::TreeViewColumn* pColumn = m_TreeView.get_column(cols_count - 1);
if(pColumn) {
pColumn->add_attribute(cell->property_value(), columns.store_pict);
}

Related

QTableWidget with setItem cannot access the data in the tablewidget

void IdListForTrain::SetListIdInList(QStringList IdList)
{
QTableWidgetItem *item=nullptr;
for(int index=0;index<IdList.count();index++)
{
ui->Id_tableWidget->insertRow(index);
for(qint32 columnIndex=0;columnIndex<=1;columnIndex++)
{
item = new QTableWidgetItem;
if(columnIndex==0)
{
ui->Id_tableWidget->setItem(index,columnIndex,item);
item->setText("00:00:00");
}
if(columnIndex==1)
{
ui->Id_tableWidget->setItem(index,columnIndex,item);
item->setText(IdList.at(index));
}
QString tmp1 = ui->Id_tableWidget->item(index,1)->text();
QString tmp = item->text();
}
}
}
Hi! I am new to Qt and I'm facing a problem. I was asked to create a tablewidget with the effective date of train Ids in one column and the names of the trains in another column,I did this code to the best of my knowledge but I can't set or access the data in the widget in the line eventhough the code doesnt give any errors but it crashes everytime I open the application window at this line,
QString tmp1 = ui->Id_tableWidget->item(index,1)->text();
I'm not sure what the reason is.
Let look at first iteration - index=0 and columnIndex=0.
You go through if(columnIndex==0) condition and set item to
QTableWidget's row = 0 (index) and column = 0 (columnIndex)
Second condition skipped
You try to access item at row = 0 (index) and column = 1 with code QString tmp1 = ui->Id_tableWidget->item(index,1)->text();. But at this time you have no item assigned to that column
That's all!

Always show a QComboBox in a cell of a QTableView

I have a QTableView with an associated model. I want to have a QComboBox in each cell of the third column.
I used a QItemDelegate as shown in this page : https://wiki.qt.io/Combo_Boxes_in_Item_Views.
It works but the combo box is only shown after double clicking in the cell, the user has to click again to show the list of possible values. This is a bit inconvenient.
Is there a way to make the combo boxes always visible ?
I'm trying with openPersistentEditor method, but it does not work right now ...
there is a bit of code close to my code (ComboBoxItemDelegate is the same than the exemple linked before):
MonWidget::MonWidget() : _ui(new Ui::MonWidget())
{
// ...
// Links Model
_linksModel = new QStandardItemModel(this);
// Links Headers
QStringList linksTableViewHeader << "Name" << "Path" << "Version";
_linksModel->setHorizontalHeaderLabels(linksTableViewHeader) ;
// Create itemDelegate for linksView
_itemDelegate = new ComboBoxItemDelegate(_ui->_linksView);
// Set the links model on the links table view
_ui->_linksView->setModel(_linksModel);
_ui->_linksView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
_ui->_linksView->horizontalHeader()->setStretchLastSection(true);
_ui->_linksView->horizontalHeader()->setMinimumSectionSize(100);
_ui->_linksView->setSelectionBehavior(QAbstractItemView::SelectRows);
_ui->_linksView->setItemDelegate(_itemDelegate);
}
// AddLinksInListView : method called when I add some rows ...
void MonWidget::AddLinksInListView(QList<DataItem*> listLinks)
{
int j=0;
int initialLinksNumber = _linksModel->rowCount();
// For each link, add a row with the link information
for (int row=initialLinksNumber; row<(initialLinksNumber + listLinks.size()) ; row++)
{
for (int column = 0; column < _linksModel->columnCount(); column++) {
//item used to display information for each column in the table view of links contained in the collection
QStandardItem *item=0;
switch(column)
{
case MonWidget::NAME:
{
item = new QStandardItem(listLinks.at(j)->data(MonWidget::NAME).toString());
_linksModel->setItem(row, column, item);
break;
}
case MonWidget::PATH:
{
item = new QStandardItem(listLinks.at(j)->data(MonWidget::PATH).toString());
_linksModel->setItem(row, column, item);
break;
}
case MonWidget::VERSION:
{
item = new QStandardItem(listLinks.at(j)->data(MonWidget::PATH).toString());
_linksModel->setItem(row, column, item);
_ui->_linksView->openPersistentEditor(_linksModel->index(row, column));
break;
}
}
}
j++;
}
}
Yes, there is a way, using openPersistentEditor. Assuming your model is named myModel:
YourDelegate* comboDelegate = new YourDelegate(this);
setItemDelegateForColumn(2, comboDelegate); // delegate set for the third column
...
// when adding a new line, use this.
// The combo box will be always visible
openPersistentEditor(myModel->index(iRow, 1));

How do I add a ComboBox to a TreeView column?

In Gtkmm, I want to have a Gtk TreeView with a ListStore, and have one of the columns in the list be a ComboBoxText. But I can't seem to figure out how to do it.
What I currently have looks like:
class PlayerListColumns : public Gtk::TreeModelColumnRecord
{
public:
PlayerListColumns()
{ add(name); add(team);}
TreeModelColumn<string> name;
TreeModelColumn<ComboBoxText*> team;
}
Then when setting the TreeView (the player_list_view object)
PlayerListColumns *columns = new PlayerListColumns();
Glib::RefPtr<ListStore> refListStore = ListStore::create(*columns);
player_list_view->set_model(refListStore);
ComboBoxText *box = manage(new ComboBoxText());
box->append("Blah");
box->append("Blah");
box->append("Blah");
TreeModel::Row row = *(refListStore->append());
row[columns->name] = "My Name";
row[columns->team] = box;
The column "name" shows up just fine, but no ComboBox. I'm almost positive that simply having a pointer to a combo box as the column type is wrong, but i don't know how it's supposed to go. I do get GTK warning:
GLib-GObject-WARNING **: unable to set property text' of typegchararray' from value of type `GtkComboBoxText'
Which seems to indicate (from a small bit of Googling) that there isn't a default renderer for non-basic types. But I haven't been able to find any examples of how to set one up, if that were the problem. All the tutorials only show TreeViews with primitive data types.
Anyone know how to put a ComboBox into a TreeView?
Okay, I haven't gotten it working 100%, but this example class should get you on the right track:
http://svn.gnome.org/svn/gtkmm-documentation/trunk/examples/book/treeview/combo_renderer/
Basically you need to add a Gtk::TreeModelColumn<Glib::RefPtr<Gtk::ListStore> > to your columns class and a Gtk::TreeModelColumn<string> to hold the selected data.
Then, to make a column a combobox, you have to add:
//manually created column for the tree view
Gtk::TreeViewColumn* pCol = Gtk::manage(new Gtk::TreeViewColumn("Choose"));
//the combobox cell renderer
Gtk::CellRendererCombo* comboCell = Gtk::manage(new Gtk::CellRendererCombo);
//pack the cell renderer into the column
pCol->pack_start(*comboCell);
//append the column to the tree view
treeView->append_column(*pCol);
//this sets the properties of the combobox and cell
//my gtkmm seems to be set for Glibmm properties
#ifdef GLIBMM_PROPERTIES_ENABLED
pCol->add_attribute(comboCell->property_text(), columns->team);
//this is needed because you can't use the ComboBoxText shortcut
// you have to create a liststore and fill it with your strings separately
// from your main model
pCol->add_attribute(comboCell->property_model(), columns->teams);
comboCell->property_text_column() = 0;
comboCell->property_editable() = true;
#else
pCol->add_attribute(*comboCell, "text", columns->team);
pCol->add_attribute(*comboCell, "model", columns->teams);
comboCell->set_property(text_column:, 0);
comboCell->set_property("editable", true);
#endif
//connect a signal so you can set the selected option back into the model
//you can just have a column that is not added to the view if you want
comboCell->signal_edited()
.connect(sigc::mem_fun(*this,&ComboWindow::on_combo_choice_changed));
EDIT ABOVE
I think something along the lines of using a Gtk::CellRendererCombo* is the way to go in your PlayerListColumns
http://developer.gnome.org/gtkmm/stable/classGtk_1_1CellRendererCombo.html
(I haven't made a working test yet, but I got the idea from:
http://developer.gnome.org/gtkmm-tutorial/unstable/sec-treeview.html.en#treeview-cellrenderer-details)

How to remove all rows and child rows from QTreeview

I don't know why I have trouble removing all rows and sub rows from qtreeview
I'm using QStandardItemModel as the model. Now here is my code that doesn't work.
What could be the problem?
QModelIndex FirstQModelIndex;
QModelIndex parentQModelIndex;
int iMdlChidCound = m_model->hasChildren();
if(iMdlChidCound > 0)
{
// only if there at list 1 row in the view
FirstQModelIndex = m_model->item(0,0)->index();
QStandardItem* feedItem = m_model->itemFromIndex(FirstQModelIndex);
// get the parent of the first row its the header row
QStandardItem* parentItem = feedItem->parent();
// here im getting exception
int parent_rows= parentItem->hasChildren();
parentQModelIndex = m_model->indexFromItem(parentItem);
// now i like to delete all the rows under the header , and its dosnt work
if(parent_rows>0)
{
bool b = feedItem->model()->removeRows(0,y,parentQModelIndex);
}
}
It seems like a lot of what you're doing is superfluous. If your only goal is to remove all the rows from the model, you could probably just use QStandardItemModel::clear
In your code you're jumping between the model and the items in a way you don't have to.
if(m_model->hasChildren()) {
m_model->removeRows(0, m_model->rowCount());
}
That should do what you're seeking.
QStandardItemModel::clear()
Which clears all the items including the header rows.

QTableView with icons in rows

I have a QTableView showing rows of a database table. In this table I have a column called data type and I have icon images for each type. How can I add these icons in front of each data type?
Here's a part of my code as requested by justanothercoder.
QString msgQueryString = "select MESSAGE_ID, DATA_TYPE from SER_MESSAGES where MESSAGE_ID > 500 ";
serendibMsgTableModel->setQuery(msgQueryString, *database);
serendibMsgTableModel->setHeaderData(0, Qt::Horizontal, tr("Message ID"));
serendibMsgTableModel->setHeaderData(1, Qt::Horizontal, tr("Data Type"));
serendibMsgProxyModel->setSourceModel(serendibMsgTableModel);
serendibMsgView->setModel(serendibMsgProxyModel);
"serendibMsgTableModel" is a QSqlQueryModel and "serendibMsgProxyModel" is a customized QSortFilterProxyModel. "serendibMsgView" is the QTableView I need the icons to be displayed, in the Data Type column.
Hope this helps for your answer.
I saw that you've already picked an answer but since you are learning Qt I'll add a few things.
Taking a look at the excellent Qt documentation I suggest you overwrite this in your model:
QVariant QSqlTableModel::data (
const QModelIndex & index,
int role = Qt::DisplayRole ) const   [virtual]
There are various roles (int role = Qt::DisplayRole):
enum Qt::ItemDataRole :
Each item in the model has a set of
data elements associated with it, each
with its own role. The roles are used
by the view to indicate to the model
which type of data it needs. Custom
models should return data in these
types.
Qt::DecorationRole : The data to be
rendered as a decoration in the form
of an icon. (QColor, QIcon or Qpixmap)
Thus, what you need to do is return a QIcon or QPixmap in the data() function for the DisplayRole.
Another approach which might be more appropriate is to make use of delegates: For example ColorListEditor
Set the DecorationRole of your items to the QPixmap you want and it should work.
edit:
I guess that the icon depends on the value in the data type column.
int rowCount = serendibMsgTableModel->rowCount();
for(int row = 0; row < rowCount; row++)
{
QModelIndex index = serendibMsgTableModel->index(row, 1);
QVariant value = serendibMsgTableModel->data(index);
static QPixmap s_invalidIcon(PATH_TO_INVALID_ICON);
static QPixmap s_type1Icon(PATH_TO_TYPE1_ICON);
static QPixmap s_type2Icon(PATH_TO_TYPE2_ICON);
QPixmap icon(s_invalidIcon);
if(value.toString() == "type1")
{
icon = s_type1Icon;
}
else if(value.toString() == "type2")
{
icon = s_type2Icon;
}
serendibMsgTableModel->setData(index, icon, Qt::DecorationRole);
}
Something like this should work.
Set the values before setModel.
I haven't tested it, but I think you should get the idea from this.