Using a QListView or similar effectively in Qt4 - c++

I am slowly getting used to using the Qt4 GUI framework. In a project I am working on, I need to be able to add/edit/remove Team objects in a list. Coming from a C#.NET perspective, I would do something like
List<Team> teams = new List<Team>();
teamsListBox.DataSource = teams;
teamsListBox.DisplayMember = "Name";
Then use buttons on the form to do the adding/removing/editing.
But, from what I can tell, there is no easy way to do this in Qt. I have looked over the documentation for QListView, QListWidget, QStandardItemModel, etc. but I cannot figure out how to get the equivalent Qt code for the C#.
My objective is to show the Teams in a list box of some kind, then be able to add/remove/edit the Teams underneath it at runtime.
How would you do this?

You should have a look at QAbstractItemModel and QStandardItemModel or create a customized TeamItemModel class for your teams that inherits from QAbstractItemModel. Those customized class will manage how the items are displayed in the Widget like QListView.
A simple for QString item example with QStringList:
QStringList list;
list << "item1" << "item2" << "item3" << "item4" << "item5";
ui->listView->setModel(new QStringListModel(list));
Then adding/removing/updating a Team should be easier than what you have tried.
Hope that helps.

Related

What's the accepted way to fill a QComboBox defined in QtQuick QML, from C++?

I want to populate a QComboBox defined in QML from my C++ code. I have seen two possible ways to do this:
Define a list (as a QStringList for example) from the C++ code, and expose it as Q_ELEMENT. Then access that list from the C++, by saying model: backend.qlist assuming the list is defined in backend. Or
Find the QComboBox in the C++ code by using view.rootObject()->findChild(). Then use addItem() to populate the list.
What is best practice?
By far the first option!
QML stands for Qt Modeling Language, following the model-view architecture, in which the model (here C++) should not know anything about the view (QML).
The first option works very well. The implementation is easy. From C++ side create a method to return a list:
QVariantList getList()
{
QVariantList list;
list << "Op1";
list << "Op2";
list << "Op3";
return list;
}
And then call the method by QML like this:
comboBoxReader.model = backend.getList()

Including a button in a WTableView

I'm working on a Wt-based gui, and struggling with something that feels like it should be very simple:
The gui displays 'events'. In our project we have a model (ActiveEventsModel, based on WStandardItemModel) and a view, (ActiveEventsView, based on WTableView). Currently the view simply shows some text corresponding to various properties of the 'events'. The aim is to add an additional column to the table, contain a button (for example, a WPushButton) which allows the user to "acknowledge" the event shown in that row (in context, this essentially translates to dismissing the event - i.e. each event has a button, and clicking the button will remove that event from the model).
I searched online and found this discussion on the Wt-forum, which contains some guidance on putting a button in (derive from WAbstractItemDelegate and use setItemDelegateForColumn) and a code example for creating a button in an item delegate. After some minor changes for Wt-4.0 compatibility I now have my button in the table.
I've defined a very simple class, EventDelegate, derived from WAbstractItemDelegate:
header:
#include <Ui/WebToolkit.h> //convenience header containing all of the Wt elements we use
class EventDelegate : public Wt::WAbstractItemDelegate
{
public:
EventDelegate();
std::unique_ptr<Wt::WWidget> update(Wt::WWidget *widget, const Wt::WModelIndex &index,
Wt::WFlags<Wt::ViewItemRenderFlag> flags) override;
void acknowledge(Wt::WModelIndex &index);
};
source:
#include <Ui/EventDelegate.h>
EventDelegate::EventDelegate()
: WAbstractItemDelegate()
{
}
std::unique_ptr<Wt::WWidget> EventDelegate::update(Wt::WWidget *widget, const Wt::WModelIndex &index,
Wt::WFlags<Wt::ViewItemRenderFlag> flags)
{
std::unique_ptr<Wt::WWidget> w = std::make_unique<Wt::WPushButton>("acknowledge");
Wt::WPushButton *button = dynamic_cast<Wt::WPushButton*>(w.get());
button->clicked().connect(std::bind(&EventDelegate::acknowledge,this,index));
return w;
}
void EventDelegate::acknowledge(Wt::WModelIndex &index) {
//how do I interact with the model?
}
This seemed promising at first, but I just can't figure out how to actually make the button do anything to the model. I thought maybe I need to override WAbstractItemDelegate::setModelData, but for that I need the model, which the ItemDelegate doesn't seem to know anything about.
I do have the ModelIndex, and the ModelIndex knows which Model it belongs to - but will only give me it as const, which is no use to me because setModelData needs to alter it.
Should I just be giving the Model to the Delegate directly, for example as a constructor parameter? That seems an easy solution but feels very inelegant. Or am I just barking up the wrong tree entirely with how I'm trying to do this? I'm extremely new to Wt (and my colleagues only a little less so - this is a relatively new project and the first in our company that's used Wt) so that's very possible.
(I've not included a whole mcve because I'm pretty sure that what I'm missing here is conceptual. I can add one later if people feel it's really necessary to answer the question)

QListWidgetItem with Radio Button

I'm working on my first QT application and I have a problem with QListWidgetItems.
I will be having different kind of list.
for checkboxed list using:
listElement[i]->setFlags(Qt::ItemIsEnabled);
listElement[i]->setCheckState(Qt::Unchecked);
works exactly as wanted.
But now I want a Radio Button list. so my question is in two parts
can use the same logic that I used for checkBox to create Radio Buttons?
I have used:
listElement[i]->setFlags(Qt::ItemIsEnabled);
QRadioButton *radio1 = new QRadioButton(0);
dlList->setItemWidget(listElement[i],radio1);
this will display Items in the list with a radio Button, the problem is that the text is Over the Radio Button:
going to try to demonstrate without image
This is a test
o
for elements 1
instead for checkbox I have
This is a test
[]
for element 1
how can I get the radioButton to align correctly with text?
New Questions:
Thanks alot for the answers my text is next to my RadioButton now.
Only thing there is no WordWrap, My text is Longer than maximum Size of the RadioButton. How can I get it to wordwrap:
rButton = new QRadioButton();
rButton->setFixedSize(LIST_TEXT_WIDTH_WO_ICON, LIST_TEXT_HEIGHT);
rButton->setStyleSheet("border:none");
rButton->setFont(segoe18Font);
rButton->setText("This is just a test for elementsss of type euh!!!");
rButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
dropListWidget->setItemWidget(listElement, rButton);
As you may have read, there are two approaches to achieve what you want.
The most flexible one: use a QListView, implement a new delegate and a model if necessary.
Keep using the classic item-based interface (QListWidget) and change the item's widgets either by sub-classing QListWidgetItem or calling QListWidgetItem::setItemWidget.
Since the question points towards the second one, I'll try to provide the simplest item-based solution.
The following piece of code generates the list widget in the picture.
QListWidgetItem *it;
it = new QListWidgetItem(ui->listWidget);
ui->listWidget->setItemWidget(it, new QRadioButton(tr("Item 1")));
it = new QListWidgetItem(ui->listWidget);
ui->listWidget->setItemWidget(it, new QRadioButton(tr("Item 2")));
// .
// .
// .
it = new QListWidgetItem(ui->listWidget);
ui->listWidget->setItemWidget(it, new QRadioButton(tr("Item N")));
where ui->listWidget is a pointer to the QListWidget that holds the items.
I hope this helps. As far as I understand, that's what you need.

Do I need to implement my own QAbstractTableModel?

I found this question: How to change the background color for a QTreeView Header (aka QHeaderView)?
I want to be able to set the color for each header section. So the question seen above seems to be my solution!
The solution says "the easiest way to do that is probably to derive a new model from QAbstractItemModel or another model class and reimplement the headerData()". I went and looked at the Qt source tree for QTableWidget, QTableModel, QTableWidgetItem... these classes are supposedly "default models" so I thought they would be a good example and then I would go implement my own QAbstractTableModel.
The 3 files I saw are a whopping 3300 lines of code. That is definitely NOT "the easiest way" IMO!!!
I would like the functionality of QTableWidget but then I want to add the following ability:
horizontalHeader.setSectionColor(index,color)
verticalHeader.setSectionColor(index,color)
Do I really need to inherit/implement QAbstractTableModel if all I want is to change the color of a section header?
Update:
I am not using my own custom view and model classes. I am using the convenience class QTableWidget right now (it is called a convenience class b/c it implements the view and model). The function headerData() is part of the model. The model class, QTableModel, is not accessible via Qt lib/headers so I can't inherit from it.
Update:
I tried creating a new item with background brush QBrush(QColor(Qt::red)) and then setting the table's header with the new item (using QTableWidget::setHorizontalHeaderItem(int column, QTableWidgetItem *item). I also tried inheriting QTableWidgetItem and overriding the virtual data() method with:
QVariant HeaderItem::data(int role) const
{
if(role==Qt::BackgroundRole) {
return QVariant(QBrush(QColor(Qt::red)));
} else if(role==Qt::ForegroundRole) {
return QVariant(QBrush(QColor(Qt::green)));
} else {
return QTableWidgetItem::data(role);
}
}
I can change the header sections foreground. But when I try to change the header's background brush... nothing happens... it's like the QTableWidgetItem's background brush that I set for the header section is ignored.
Instead of creating model with custom headerData() from scratch create subclass of QTableWidgetItem with desired implementation of QTableWidgetItem::data() and use the instances of this class for QTableWidget::setHorizontalHeaderItem.

Changing a Widget's name based on a string read in from an XML form in Qt

I'm writing a code for a voting machine that will allow user to read in custom XML ballots and then vote on them, however in the current build I have in QtCreator, I don't see an easy way to edit buttons in my GUI directly. In the code snippet below, I assign an element to pull out the names and type of ballot being read in, but I need to append a label on the GUI as well as change buttons to the names of candidates read in. Any ideas on how to do this?
while(!n.isNull()){
QDomNode x = n.firstChildElement();
QDomElement e = n.toElement();
QMessageBox::information(0,
tr( "Loading Element" ),
tr( "Our element is %1" ).arg(e.tagName()) );
QDomElement p = x.firstChildElement();//p finds Races
QMessageBox::information(0,tr("Foo"),tr("p = %1").arg(p.text()));//finds Race and Ballot types
n = n.nextSibling();
}
}
All the widgets you created using the Designer UI are available from your code. How to access them depends on how you linked your UI with the rest of your classes (see http://doc.qt.io/archives/4.6/designer-using-a-ui-file.html) but if you used the multiple inheritance approach your widgets and layouts will be accessible directly from your class using the name under which they appear in Designer. Qt Creator's completion will even work with them.
Having that in mind you can easily use the usual methods to change a widget's name, add a label to a layout, etc.
If this is still unclear, please add the code you use to embed your GUI, as it is needed in order to give you a sensible code example.