How do I add a ComboBox to a TreeView column? - c++

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)

Related

How to Add processBar inside QTreeWidget cloum

Is there any way in Qt to Add a processBar inside one of QTreeWidget items
Something like this
http://doc.qt.io/qt-5/qtreewidget.html#setItemWidget will do the job for you
just call it for each row with whatever widget you need.
cheers
/edit:
lets say your column 'status' has column index 5, then it would be something like this:
QTreeWidgetItem* item = new QTreeWidgetItem(columnTextsStringList);
/*insert into tree here*/
QProgressBar* progBar = new QProgressBar;
treeWidget->setItemWidget(item, 5/*column of the status*/, progBar);
// no need to delete progBar, its now a child of treeWidget
// use progBar

QT C++ Framework QlistwidgetItem CONVERSION

I have a list you can fill it on your own with QfileDialog and put the selected files in a widgetList.
I can access the list and colour all those items and do whatever I want to, except this one problem:
I would like to select one item from the list and convert it somehow to QStringList so I can use it as a Phonon MediaSource.
I don't know how I can extract this item, I want the text shown in ListWidget and put it in my mediaObj so I can play it.
Here is a little bit of my code:
How i open the FileDialog (works):
QStringList fileNames;
QFileDialog fDialog(this);
fDialog.setFileMode(QFileDialog::AnyFile);
fDialog.setNameFilter(tr("Music(*.mp3)"));
fDialog.setViewMode(QFileDialog::Detail);
while (true) {
if (fDialog.exec()) {
fileNames = fDialog.selectedFiles();
widget.list->addItems(fileNames);
musicObj->enqueue(fileNames.last());
} else {
break;
}
}
How I access one item clicked in the list:
QListWidgetItem *list_itm = widget.list->currentItem();
list_itm->setTextColor(Qt::red);
But I can extract the string shown on my cursor position.
QListWidgetItem *list_itm = widget.list->currentItem();
list_itm->setTextColor(Qt::red);
QStringList list;
list << list_itm.text();
Unless I've misunderstood, you just want a QStringList with a single item in, the current widget item.

GTKmm - How to put a pixbuf in a treeview

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);
}

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.

QComboBox - set selected item based on the item's data

What would be the best way of selecting an item in a QT combo box out of a predefined list of enum based unique values.
In the past I have become accustomed to .NET's style of selection where the item can be selected by setting the selected property to the item's value you wish to select:
cboExample.SelectedValue = 2;
Is there anyway to do this with QT based on the item's data, if the data is a C++ enumeration?
You lookup the value of the data with findData() and then use setCurrentIndex()
QComboBox* combo = new QComboBox;
combo->addItem("100",100.0); // 2nd parameter can be any Qt type
combo->addItem .....
float value=100.0;
int index = combo->findData(value);
if ( index != -1 ) { // -1 for not found
combo->setCurrentIndex(index);
}
You can also have a look at the method findText(const QString & text) from QComboBox; it returns the index of the element which contains the given text, (-1 if not found).
The advantage of using this method is that you don't need to set the second parameter when you add an item.
Here is a little example :
/* Create the comboBox */
QComboBox *_comboBox = new QComboBox;
/* Create the ComboBox elements list (here we use QString) */
QList<QString> stringsList;
stringsList.append("Text1");
stringsList.append("Text3");
stringsList.append("Text4");
stringsList.append("Text2");
stringsList.append("Text5");
/* Populate the comboBox */
_comboBox->addItems(stringsList);
/* Create the label */
QLabel *label = new QLabel;
/* Search for "Text2" text */
int index = _comboBox->findText("Text2");
if( index == -1 )
label->setText("Text2 not found !");
else
label->setText(QString("Text2's index is ")
.append(QString::number(_comboBox->findText("Text2"))));
/* setup layout */
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(_comboBox);
layout->addWidget(label);
If you know the text in the combo box that you want to select, just use the setCurrentText() method to select that item.
ui->comboBox->setCurrentText("choice 2");
From the Qt 5.7 documentation
The setter setCurrentText() simply calls setEditText() if the combo
box is editable. Otherwise, if there is a matching text in the list,
currentIndex is set to the corresponding index.
So as long as the combo box is not editable, the text specified in the function call will be selected in the combo box.
Reference: http://doc.qt.io/qt-5/qcombobox.html#currentText-prop