QT C++ SelectedIndex of QListWidget - c++

How can I get the selected index of QListWidget. I can get the selected color but now sure how can I get the selected Index of the item.
I have written the selected color function. Please help me in getting the selected index of the color.
ColorList::ColorList(QWidget *parent)
: QListWidget(parent)
{
init();
}
QString ColorList::selectedColor() const
{
return currentItem() ? currentItem()->data(Qt::UserRole).toString() : QString();
}
void ColorList::init()
{
setFrameShape(QFrame::NoFrame);
QMap<QString, QString> names;
names["Air"] = "#FFFFFF";
names["Resist"] ="#B22222";
names["BARC"] = "#F2CBC5";
names["Oxide"] = "#34AAD1";
names["Low"] = "#FD7E00";
// add color names and their icons
foreach(const QString &key, names.keys())
{
QPixmap px(16,16);
px.fill(QColor(names[key]));
QListWidgetItem *item = new QListWidgetItem(QIcon(px), key);
item->setData(Qt::UserRole, names[key]);
addItem(item);
}
}

It's currentRow(). Please see here for the documentation http://doc.qt.io/qt-4.8/qlistwidget.html#currentRow-prop

Related

Add QCombobox inside QTreeview specific cell

I was trying to insert a QCombobox only in some specific cells of my QTreeview. As I read, I think that I need to create my delegate (that I've created). But I don't understand how to insert this in my treeview.
I want to realize this:
This is my code:
#include <QTreeView>
#include <QStandardItemModel>
#include <QStandardItem>
#include "mainwindow.h"
#include "comboboxdelegate.h"
const int ROWS = 2;
const int COLUMNS = 3;
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
treeView = new QTreeView(this);
setCentralWidget(treeView);
standardModel = new QStandardItemModel ;
standardModel->setColumnCount(2);
QStandardItem *root = new QStandardItem("ROOT");
root->setCheckable(true);
root->setCheckState(Qt::Checked);
root->setEditable(false);
standardModel->setItem(0, 0, root);
QList< QStandardItem * > listOne ;
QStandardItem *f1 = new QStandardItem( "Field_1" );
f1->setCheckable(true);
f1->setCheckState(Qt::Checked);
f1->setEditable(false);
listOne.append(f1) ;
listOne.append( new QStandardItem( "<Free text>" ) ) ;
root->appendRow(listOne);
QList< QStandardItem * > listTwo ;
QStandardItem *f2 = new QStandardItem( "Field_2" );
listTwo.append(f2) ;
listTwo.append( new QStandardItem( "<HERE COMBOBOX!>" ) ) ;
root->appendRow(listTwo);
treeView->setModel(standardModel);
treeView->expandAll();
}
I managed to create an entire column with QCombobox (using custom delegate). But I don't know how to set only specific cell. Anyone can help me?
QTreeWidget makes widget items convenient.
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
treeWidget = new QTreeWidget(this);
setCentralWidget(treeWidget);
treeWidget->setColumnCount(2);
auto root = new QTreeWidgetItem({"Root"});
root->setCheckState(0, Qt::Checked);
treeWidget->addTopLevelItem(root);
auto child1 = new QTreeWidgetItem({"Field 1", "<Free Text>"});
child1->setCheckState(0, Qt::Checked);
child1->setFlags(child1->flags() | Qt::ItemIsEditable);
root->addChild(child1);
auto child2 = new QTreeWidgetItem({"Field 2"});
child2->setFlags(child2->flags() | Qt::ItemIsEditable);
root->addChild(child2);
auto comboBox = new QComboBox();
comboBox->addItems({"Red", "Blue", "Yellow"});
treeWidget->setItemWidget(child2, 1, comboBox);
connect(treeWidget, &QTreeWidget::itemDoubleClicked, treeWidget, &QTreeWidget::editItem);
treeWidget->expandAll();
}
There are a few differences to note.
You'll need QTreeWidget* treeWidget; in your class declaration. And include the QTreeWidget header.
By default, TreeWidgetItems aren't checkable (no checkbox), but calling QTreeWidgetItem::setCheckState with Qt::Checked or Qt::Unchecked will make it checkable.
Items are not editable by default. Whole rows can be made editable by calling treeWidgetItem->setFlags(treeWidgetItem->flags() | Qt::ItemIsEditable). To filter what rows/columns can be edited, you can define your own itemDoubleClicked slot and use an if-statement (example).
You need to store combobox items in model item, for example using Qt::UserRole
QStringList options = {"one", "two", "three"};
QStandardItem* item = new QStandardItem(options[0]);
item->setData(QVariant(options),Qt::UserRole);
listTwo.append(item);
Then you need assign delegate to view. You can assign it for the whole table and return default delegate if index.data(Qt::UserRole).isNull().
Delegate* delegate = new Delegate(treeView);
treeView->setItemDelegate(delegate);
It's probably a good idea to set edit triggers to all, so dropdown occurs not only on doubleclick but also on single click
treeView->setEditTriggers(QAbstractItemView::AllEditTriggers);
Delegate must implement createEditor, setEditorData and setModelData
QWidget *Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.data(Qt::UserRole).isNull()) {
return QStyledItemDelegate::createEditor(parent, option, index);
}
return new QComboBox(parent);
}
void Delegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QComboBox* comboBox = qobject_cast<QComboBox*>(editor);
if (!comboBox) {
return QStyledItemDelegate::setEditorData(editor, index);
}
QStringList options = index.data(Qt::UserRole).toStringList();
comboBox->addItems(options);
QString value = index.data().toString();
int current = options.indexOf(value);
if (current > -1) {
comboBox->setCurrentIndex(current);
}
comboBox->showPopup();
}
void Delegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox* comboBox = qobject_cast<QComboBox*>(editor);
if (!comboBox) {
return QStyledItemDelegate::setModelData(editor, model, index);
}
model->setData(index, comboBox->currentText());
}
By default delegate doesn't change how item is displayed and show editor only if edit is triggered: no combobox is shown. But you can override it with custom paintEvent.
void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.data(Qt::UserRole).isNull()) {
return QStyledItemDelegate::paint(painter, option, index);
}
QStyle* style = qApp->style();
QStyleOptionComboBox opt;
opt.rect = option.rect;
opt.currentText = index.data().toString();
opt.palette = option.palette;
opt.state = option.state;
opt.subControls = QStyle::SC_All;
opt.activeSubControls = QStyle::SC_All;
opt.editable = false;
opt.frame = true;
style->drawComplexControl(QStyle::CC_ComboBox, &opt, painter, 0);
style->drawControl(QStyle::CE_ComboBoxLabel, &opt, painter, 0);
}
Full source here: combobox-delegate

How to drag and drop a specific QPixmap into a QGraphicsView?

On a subclassed QListWidget I have several items. Every QListWidget item (e.g. "ROS Init", "Images" etc) that is shown below is associated with a specific icon.
The problem I have is that I am trying to drag and drop the specific icon corresponding to that QListWidget item, but nothing happens.
Below the function responsible for the dragging:
void ListView::startDrag(Qt::DropActions supportedActions)
{
QMap<int, QString> icons;
icons.insert(IT_RosInit, "ROS Init");
icons.insert(IT_Images, "Images");
icons.insert(IT_Path, "Path");
icons.insert(IT_RosShutDown, "ROS Shutdown");
if (supportedActions & Qt::CopyAction)
{
const QList<QListWidgetItem *> &m_items(selectedItems());
if (m_items.isEmpty())
return;
QPixmap pixmapLaser("/home/images/laserscan.png");
QPixmap pixmapPCloud2("/home/images/pcloud2.png");
// etc ...
QStringList iconImages;
for(int i = 0; i < icons.count(); ++i)
{
for (const QString &tableType : iconImages) {
if (tableType == "ROS Init")
{
auto *data = mimeData(m_items);
auto *drag = new QDrag(this);
drag->setPixmap(pixmapLaser);
drag->setMimeData(data);
drag->setHotSpot(pixmapLaser.rect().center());
drag->exec(Qt::CopyAction);
}
else if(tableType == "Images")
{
auto *data2 = mimeData(m_items);
auto *drag2 = new QDrag(this);
drag2->setPixmap(pixmapPCloud2);
drag2->setMimeData(data2);
drag2->setHotSpot(pixmapPCloud2.rect().center());
drag2->exec(Qt::CopyAction);
}
}
}
}
else
{
QListWidget::startDrag(supportedActions);
}
}
After subclassing the QListWidget I just reimplemented the usual drag and drop function. All other function are working properly but the startDrag and in fact as I try to drag the proper QPixmap, I actually see nothing being dragged.
I consulted this source, useful, and also this other source which was useful but it didn't reimplement the startDrag but instead dropEvent which for me is not a problem because that is working well.
I also consulted this source and this other source but that also didn't help fixing the problem.
Thanks for shedding light on this matter for solving the problem
Solution
I would approach this problem in the following way:
Set the ItemIsDragEnabled flag of QListWidgetItem to enable the item for dragging:
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
Set the desired data for each item:
item->setData(Qt::UserRole, type);
where type is one of the enumerated values IT_RosInit, IT_Images, etc.
Enable the drag functionality of the ListWidget:
setDragEnabled(true);
setDragDropMode(QAbstractItemView::DragOnly);
Use the item settings to setup the QDrag object, created in startDrag.
Example
Here is an example I have prepared for you to demonstrate how the proposed solution could be implemented:
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent)
{
auto *l = new QVBoxLayout(this);
auto *list = new ListView(this);
list->addItem(createItem(":/pix/images/laserscan.png", tr("RosInit"), IT_RosInit));
list->addItem(createItem(":/pix/images/icons/pcloud2.png", tr("Images"), IT_Images));
list->addItem(createItem(":/pix/images/icons/some_icon.png", tr("Path"), IT_Path));
list->addItem(createItem(":/pix/images/icons/another_icon.png", tr("RosShutDown"), IT_RosShutDown));
l->addWidget(list);
resize(300, 400);
setWindowTitle("IconDrag");
}
QListWidgetItem *MainWindow::createItem(const QString &pm, const QString &text, int type)
{
auto *item = new QListWidgetItem(QIcon(QPixmap(pm)), text);
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
item->setData(Qt::UserRole, type);
return item;
}
ListView.cpp
ListView::ListView(QWidget *parent) :
QListWidget(parent)
{
setDragEnabled(true);
setDragDropMode(QAbstractItemView::DragOnly);
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::SingleSelection);
}
void ListView::startDrag(Qt::DropActions supportedActions)
{
if (supportedActions & Qt::CopyAction) {
const QList<QListWidgetItem *> &items(selectedItems());
if (items.isEmpty())
return;
const QPixmap &pm(items.first()->icon().pixmap(64));
auto *item = items.first();
auto *mimeData = new QMimeData();
auto *drag = new QDrag(this);
mimeData->setData("text/plain", item->data(Qt::UserRole).toByteArray());
drag->setPixmap(pm);
drag->setMimeData(mimeData);
drag->setHotSpot(pm.rect().center());
drag->exec(Qt::CopyAction);
}
}

Qt - How to show image/icon/data while dragging an item?

I have an application where I can drag an item to a QGraphicsScene and create a new object depending on the item text, but how can I change the data being displayed while moving around the item?
for example, instead of a text, I want to show an icon:
I have a list with some itens:
OptionList::OptionList(QWidget *parent) : QListWidget(parent)
{
this->setDragEnabled(true);
this->setDropIndicatorShown(true);
this->setSelectionMode(QAbstractItemView::SingleSelection);
this->setDefaultDropAction(Qt::CopyAction);
this->setViewMode(QListView::ListMode);
for(const QString &color : {"Blue", "Red", "Green", "Yellow"})
{
OptionItem *item = new OptionItem;
item->setText(color);
item->setFlags(Qt::ItemIsEnabled| Qt::ItemIsSelectable| Qt::ItemIsDragEnabled);
addItem(item);
}
}
I drop the itens into the scene to create a new object:
MyScene::MyScene()
{
setBackgroundBrush(Qt::lightGray);
}
void MyScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
event->setAccepted(true);
}
void MyScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
event->setAccepted(true);
}
void MyScene::dropEvent(QGraphicsSceneDragDropEvent *event)
{
QByteArray encoded = event->mimeData()->data("application/x-qabstractitemmodeldatalist");
QDataStream stream(&encoded, QIODevice::ReadOnly);
QStringList colors;
while (!stream.atEnd())
{
int row, col;
QMap<int, QVariant> roleDataMap;
stream >> row >> col >> roleDataMap;
colors << roleDataMap[Qt::DisplayRole].toString();
}
QPointF posView = event->scenePos() ;
for(const QString & color: colors)
{
Block *newBlock = new Block(color);
newBlock->setPos(posView);
addItem(newBlock);
}
}
Then, I created OptionItem class, derived from QListWidgetItem, and reimplemented the mousePressEvent, mouseMoveEvent and mouseReleaseEvent
OptionItem::OptionItem()
{
}
void OptionItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
event->setAccepted(true);
}
void OptionItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QDrag *drag = new QDrag(event->widget());
QMimeData *mime = new QMimeData;
QImage image(":/images/MyIcon_icon.png");
mime->setImageData(image);
drag->setMimeData(mime);
drag->setPixmap(QPixmap::fromImage(image));
drag->setHotSpot(QPoint(15, 30));
drag->exec();
event->setAccepted(true);
}
void OptionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
event->setAccepted(true);
}
I tried to follow the drag drop robot example in the Qt Creator but it isn't the same thing
It seems that the image appears very quickly when I start dragging an item
Is there a way to show the icon while dragging the item through the whole operation?
The classes that inherit from QAbstractItemView support the default drag so they already have implemented methods, instead the example you point out shows how to implement this functionality for some class that does not have it, the task in your case is simple, you must overwrite the method startDrag of QListWidget.
optionilist.h
#ifndef OPTIONLIST_H
#define OPTIONLIST_H
#include <QListWidget>
class OptionList: public QListWidget{
public:
OptionList(QWidget* parent=nullptr);
protected:
void startDrag(Qt::DropActions supportedActions);
};
#endif // OPTIONLIST_H
optionlist.cpp
#include "optionlist.h"
#include <QDrag>
OptionList::OptionList(QWidget *parent): QListWidget(parent){
setDragEnabled(true);
setDropIndicatorShown(true);
setSelectionMode(QAbstractItemView::SingleSelection);
setDefaultDropAction(Qt::CopyAction);
setViewMode(QListView::ListMode);
for(const QString &color : {"Blue", "Red", "Green", "Yellow"}){
QListWidgetItem *blue = new QListWidgetItem;
blue->setText(color);
blue->setFlags(Qt::ItemIsEnabled| Qt::ItemIsSelectable| Qt::ItemIsDragEnabled);
addItem(blue);
}
}
void OptionList::startDrag(Qt::DropActions supportedActions){
if(supportedActions & Qt::CopyAction){
QList<QListWidgetItem *> m_items = selectedItems();
if(m_items.isEmpty())
return;
QMimeData *data = mimeData(m_items);
QDrag *drag = new QDrag(this);
QPixmap pixmap(":/images/MyIcon_icon.png");
drag->setPixmap(pixmap);
drag->setMimeData(data);
drag->setHotSpot(pixmap.rect().center());
drag->exec(Qt::CopyAction);
}
else
QListWidget::startDrag(supportedActions);
}
The complete code can be found at the following link.
The above is correct!
Also should note that drag->setMimeData(data); needs to be called after drag->setPixmap(pixmap);.
Otherwise, during the drag moving, it will show the original mimedata type instead of showing an image/icon.

Retrieve QComboBox index from QCompletion popup

I have a QComboBox with a QCompleter. The QCompleter displays suggestions in a popup list and I'm drawing the elements in a custom way.
The problem is: I can't get the index in the original combobox even if I did store it into the UserData of the item.
Complete code follows:
class MyItemDelegate: public QItemDelegate {
public:
MyItemDelegate(QWidget *parent) :
QItemDelegate(parent) {}
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index ) const Q_DECL_OVERRIDE
{
if (index.row() == 0) { // If this is the first item in the POPUP VIEW
auto comboIndex = index.data(Qt::UserRole).toInt();
qDebug() << "Combobox index is " << comboIndex; // WRONG!!
}
... custom styling code omitted since off-topic ...
}
};
MyWindow::MyWindow(QStringList words, QMainWindow *parent) :
QDialog((QWidget*)parent),
ui(new Ui::MyWindow) {
ui->setupUi(this);
int comboBoxIndex = 0;
for(auto& word : words) {
ui->myComboBox->addItem(word, comboBoxIndex); // This is stored in UserData
++comboBoxIndex;
}
completer = new QCompleter(words, this);
// Use a TreeView for the popup of the completer
QTreeView *treeView = new QTreeView(this);
completer->setPopup(treeView);
treeView->setItemDelegate(new MyItemDelegate(this));
}
No matter what element I have first in the QCompletion popup list, the qDebug() line always returns 0 as index.
Isn't index.data() referring to the original item data of the combobox?
As i see, your problem is that you retrieve comboIndex from model where you didn't set UserData. You set UserData for items of internal QComboBox model (see QComboBox), but when you try to retrieve this data, you do that in code of MyItemDelegate, which you set for QTreeView for QCompleter. That's why index in paint method of delegate is index of QCompleter internal model, not index of QComboBox internal model. And that's why comboIndex is always 0.
To solve your problem you can add UserData in QCompleter internal model. For example, you can create your own model and set this model for QCompleter with method setModel.

Qt adding a derived QListwidgetitem to QListWidget

I have subclassed QTreeWidget, QTreeWidgetItem and QListWidgetItem. I am trying to add my custom QListWidgetItem to QListWidget but its not getting displayed in the view.
I Have created a dialog. I have inserted a QTreeWidget and QListWidget.
What I want is when I click a Item in QTreeWidget, The QListWidget should get populated with the my custom QListWidgetItems i.e. CustomListWidgetItems contained in the clicked CustomTreeWidgetItem (QTreeWidgetItem derived class).
If I use QListWidgetItem instead of CustomListWidgetItems, every thing works fine.
Header file contents:
class CustomTreeWidgetItem : public QTreeWidgetItem
{
public:
explicit CustomTreeWidgetItem(int type = Type);
public:
QList<CustomListWidgetItem*> projects;//Items to populate ListWidget
};
class CustomListWidgetItem : public QListWidgetItem
{
public:
explicit CustomListWidgetItem(const QIcon & icon, const QString & text, QListWidget * parent = 0, int type = Type);
CustomListWidgetItem(const int& id,QString Name,QString Description,QString icon);
public:
int Id;
QString Name;
QString Description;
QString Icon;
};
Source contents of Custom Listwidgetitem:
CustomListWidgetItem::CustomListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent, int type) : QListWidgetItem(icon,text,parent,type)
{
}
CustomListWidgetItem::CustomListWidgetItem(const int& id,QString Name,QString Description,QString icon)
{
this->Id = id;
this->Name = Name;
this->Description = Description;
this->Icon = icon;
QString iconPath = QCoreApplication::applicationDirPath() + "/" + icon + ".png";
QIcon qIcon(iconPath);
QListWidgetItem::QListWidgetItem(qIcon,Name);
}
Source contents:
void CustomTreeWidget::treeitemSelected(QTreeWidgetItem * item, int)//Tree item click event
{
CustomTreeWidgetItem *project = static_cast<CustomTreeWidgetItem*>(item);
if(LISTWIDGET)
{
m_listWidget->clear();
m_listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
int count = project->projects.count();
if(count == 0)
{
m_listWidget->addItem("No Projects Here");//This gets displayed
m_listWidget->setSelectionMode(QAbstractItemView::NoSelection);
}
else
{
for (int i = 0; i < count; ++i)
{
m_listWidget->addItem(project->projects[i]);//This does not get displayed
}
}
}
}
During Debugging I can see that the data i.e Name, Description, etc. is present in "project->projects[i]". No error is shown during addItem function call still the items are not visible in view.
Few questions:
- Why do I have the feeling you mix listwidgetitem and treewidgetitem?
- Why do you fill your view everytime an item is selected? is it initialized?
- Can you show where you create the view and start adding items?
Check you have the following:
create a qtreewidget that you add to your view layout
add a root node using something like
QTreeWidgetItem *treeItemRoot = new QTreeWidgetItem(myTreeWidget);
treeItemRoot->setText(0, projectName);
add children nodes
QTreeWidgetItem *treeItemChild = new QTreeWidgetItem();
treeItemRoot->addChild(treeItem);
and post the results.