Help needed with Combo boxes inside database WTableViews
Added by John Davidson over 10 years ago
I want to display a WT QueryModel of an database table using a WTableView, in such a way that some of the columns in the WTableView are presented as WComboBox dropdowns populated by queries to other tables. But I don't know how to do this.
I believe Koen will tell me I need to specialise the WTableView, but I don't know how to do this. I'm not a very advanced programmer and I'm not sure I've ever "specialised" anything before.
To get me started on the path to understanding, can anyone point me to/copy and paste an example of a WTableView with combo boxes in one or more of the columns? Or even WTableViews containing other widgets, so I know where to begin. Anything! I've searched and searched.
thanks in advance
John
Replies (8)
RE: Help needed with Combo boxes inside database WTableViews - Added by John Davidson over 10 years ago
Actually it's not Koen but Wim:
There are two possibilities:
If you want to show the WComboBox only when in 'edit' mode, and just the text while not editing, specialize WItemDelegate and reeimplement createEditor, editState and setEditState.
If you always want to show the combobox, specialize WAbstractItemDelegate, and implement update() so that it always renders a combobox.
Then in your WTableView, call the appropriate method to tell the view to use this delegate (e.g. WAbstractItemView::setItemDelegateForColumn())
Wim.
I read that, but I don't know how to do it!
RE: Help needed with Combo boxes inside database WTableViews - Added by John Davidson over 10 years ago
And Koen too!
Hey Mohammed,
You need to specialize WItemDelegate and use that item delegate for the particular column(s).
Regards,
koen
Please, Wim or Koen, a quick example?
RE: Help needed with Combo boxes inside database WTableViews - Added by Koen Deforche over 10 years ago
Hey John,
An example for this is indeed missing, although we've done it a few times in different internal projects.
I've created a feature request for it:
http://redmine.emweb.be/issues/3243
Regards,
koen
RE: Help needed with Combo boxes inside database WTableViews - Added by T Y over 10 years ago
Hi,
The issue is marked as resolved, but I cannot find either link to example or example coming with distribution.
I would appreciate help on the above.
Thank you.
Kind regards,
TY
RE: Help needed with Combo boxes inside database WTableViews - Added by T Y over 10 years ago
Ok. After a search for content it is found: examples/widgetgallery/examples/ComboDelegateTable.cpp
This brings me to following observation: After working with Qt and Wt, it is obvious that Wt needs to rethink presentation of documentation.
It would not hurt to provide complete examples (including configuration files). Again, Qt has good was of presenting it.
Otherwise -> Great product. I was looking for /waiting for Wt a long time.
Thank you.
Kind regards,
TY
RE: Help needed with Combo boxes inside database WTableViews - Added by Joseph Witanto almost 9 years ago
Hi, I am new to Wt C (a few weeks), and I am also trying to implement combobox at tableview
The query is from two tables (master-detail)
The combobox did appear, but it seems that when the option is selected, it isn't saved and the tableview (or the querymodel) is not changed
Anybody knows what is the problem?
Thanks for the time
#ifndef COMBO_DELEGATE_H_
#define COMBO_DELEGATE_H_
#include <Wt/WStringListModel>
#include <Wt/WTableView>
#include <Wt/WItemDelegate>
#include <Wt/WContainerWidget>
#include <Wt/WComboBox>
/*
* This delegate demonstrates how to override the editing behaviour of a
* table cell.
*
* It takes a list of possible items on construction and, when edited, saves
* the selected item from the list to the Wt::DisplayRole in the model for
* Wt::WItemDelegate to render.
* It also saves the items index for future editing (rather than each time
* searching the item in the list). This is done using the general purpose
* Wt::UserRole in the model.
*/
class ComboDelegate : public Wt::WItemDelegate {
public:
ComboDelegate(Wt::WAbstractItemModel* items)
: items_(items)
{ }
void setModelData(const boost::any &editState, Wt::WAbstractItemModel* model,
const Wt::WModelIndex &index) const
{
int stringIdx = (int)Wt::asNumber(editState);
model->setData(index, items_->data(stringIdx, 0, Wt::UserRole), Wt::UserRole);
model->setData(index, items_->data(stringIdx, 0, Wt::UserRole), Wt::DisplayRole);
}
boost::any editState(Wt::WWidget* editor) const
{
Wt::WComboBox* combo = dynamic_cast<Wt::WComboBox*>
(dynamic_cast<Wt::WContainerWidget*>(editor)->widget(0));
return combo->currentIndex();
}
void setEditState(Wt::WWidget* editor, const boost::any &value) const
{
Wt::WComboBox* combo = dynamic_cast<Wt::WComboBox*>
(dynamic_cast<Wt::WContainerWidget*>(editor)->widget(0));
combo->setCurrentIndex((int)Wt::asNumber(value));
}
protected:
virtual Wt::WWidget* createEditor(const Wt::WModelIndex &index,
Wt::WFlags<Wt::ViewItemRenderFlag> flags) const
{
Wt::WContainerWidget *const container = new Wt::WContainerWidget();
Wt::WComboBox* combo = new Wt::WComboBox(container);
combo->setModel(items_);
combo->setCurrentIndex((int)Wt::asNumber(index.data(Wt::UserRole)));
combo->changed().connect(boost::bind(&ComboDelegate::doCloseEditor, this,
container, true));
combo->enterPressed().connect(boost::bind(&ComboDelegate::doCloseEditor,
this, container, true));
combo->escapePressed().connect(boost::bind(&ComboDelegate::doCloseEditor,
this, container, false));
return container;
}
private:
Wt::WAbstractItemModel* items_;
void doCloseEditor(Wt::WWidget *editor, bool save) const
{
closeEditor().emit(editor, save);
}
};
#endif
//at main
qmDetail_ = new dbo::QueryModel<Item>();
qmDetail_->setQuery(session_.query<Item>
("select ActivityTemplateDetail, Category.name "
"from activity_template_detail ActivityTemplateDetail join category Category "
"on ActivityTemplateDetail.categoryTemplate_id = Category.id")
.where("ActivityTemplateDetail.activityTemplate_id = ?").bind(id));
qmDetail_->addColumn("ActivityTemplateDetail.id", "ID", Wt::ItemIsSelectable);
qmDetail_->addColumn("ActivityTemplateDetail.value", "ValueWt::ItemIsEditable);
qmDetail_->addColumn("categoryTemplate_id", "Category", Wt::ItemIsEditable);
WTableView * tableView = new WTableView();
tableView->setModel(qmDetail_);
WStandardItemModel *si = new WStandardItemModel();
WStandardItem *i = new WStandardItem();
i->setData(1, UserRole);
i->setText("Def");
si->appendRow(i);
i = new WStandardItem();
i->setData(2, UserRole);
i->setText("Abc");
si->appendRow(i);
ComboDelegate* customdelegate = new ComboDelegate(si);
tableView->setItemDelegateForColumn(2, customdelegate);
RE: Help needed with Combo boxes inside database WTableViews - Added by Mark O'Donovan about 8 years ago
I am having the same issue.
I believe the WTableview will not call setModelData() because editing has not been triggered.
Normally clicking/double-clicking etc. a WItemDelegate would cause WTableView to call edit().
edit() adds the index to editedItems_.
This causes isEditing() to return true in WTableView::renderWidget().
In this case renderWidget() sets the RenderEditing flag when requesting a widget from the delegate.
A WItemDelegate will then return an WLineEdit instead of a WText.
The WItemDelegate's closeEditor() signal is connected to WAbstractItemView::closeEditorWidget.
closeEditorWidget() looks something like this:
if( editor in editedItems_ )
delegate->setModelData(editState, model(), index)
So getting the delegate to return an editor is not enough, we also need to get that editor into editedItems_
Perhaps one of the experts could tell us what to do here??
RE: Help needed with Combo boxes inside database WTableViews - Added by Koen Deforche about 8 years ago
Hey,
I modified the widget gallery example just to check but the modified value is there correctly set to the model?
Wt::WPushButton *button = new Wt::WPushButton("Test", example);
button->clicked().connect(std::bind([=]() {
for (int r = 0; r < model->rowCount(); ++r) {
for (int c = 0; c < model->columnCount(); ++c) {
std::cerr << "\t" << Wt::asString(model->data(r, c));
}
std::cerr << "\n";
}
}));
gives after changing the first value:
pears apples
apples apples
Regards,
koen