QTableWidget selection rectangle does not disappear even after editing is finished - c++

I am implementing a QTableWidget, the selection rectangle seems not to be disappearing even after I finish editing and change my selection to other cells.
Below is a screenshot of the QTableWidget.
Below is the code for constructing the tablewidget, rows are added dynamically via a QPushButton:
{
setObjectName(obj_name);
layout = new QVBoxLayout();
table = new QTableWidget(this);
table->verticalHeader()->setVisible(false);
table->verticalHeader()->setDefaultSectionSize(20);
table->setFixedWidth(180);
table->setColumnCount(3);
table->setColumnWidth(0,75);
table->setColumnWidth(1, 75);
table->setColumnWidth(2, 25);
QStringList header = { "Tag", "Threshold" ,""};
table->setHorizontalHeaderLabels(header);
table->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
add = new QPushButton("+", this);
add->setObjectName("btn_threshold_add");
layout->addWidget(table);
layout->addWidget(add);
setLayout(layout);
connect(add, SIGNAL(clicked()), this, SLOT(add_row()));
}
Below is the code for add_row() SLOT, triggers when user clicked the add button:
void TagThresholdWidget::add_row()
{
int row = table->rowCount();
QPushButton *del = new QPushButton("-", table);
table->insertRow(row);
table->setCellWidget(row, 2, del);
connect(del, SIGNAL(clicked()), this, SLOT(remove_row()));
}
Anyone has any clue to how to solve this problem? Its seems like a Qt graphical paint bug to me

Related

How to recover item from a QPushButton?

I made a code in c ++ with the Qt framework.
The goal is to add lines that contain a QLabel "url", a QLineEdit "name" and QPushButton "remove".
I add the line with a QPushButton named "Add".
The part to add the line works.
The code is the following :
name=new QLineEdit("",list);
url=new QLabel("",list);
removeLine=new QPushButton("remove",list);
//list is a QListWidget
hbox=new QHBoxLayout;
hbox->addWidget(name);
hbox->addWidget(url);
hbox->addWidget(removeLine);
widget = new QWidget;
widget->setLayout(hbox);
item=new QListWidgetItem;
item->setSizeHint(QSize(0,50));
list->addItem(item);
list->setItemWidget(item,widget);
When I press the remove button, I would like the corresponding line to be deleted.
The problem is that I can not find the item of each remove button.
I tried a method with QSignalMapper but it does not work.
Here is the code:
i = list->currentRow();
signalMappper=new QSignalMapper(this);
connect(signalMappper,SIGNAL(mapped(int)),this,SLOT(removeLineEditLabelAndButton(int)));
connect(removeLine,SIGNAL(clicked()),signalMappper,SLOT(map()));
signalMappper->setMapping(removeLine,i);
//SLOT
void PanoramaWidget::removeLineEditLabelAndButton(int row){
item= list->takeItem(row);
list->removeItemWidget(item);
delete item;
}
How would you solve this problem?
Can use lambda function to connect clicked signal of QPushButton
list = new QListWidget(this);
QLineEdit * name = new QLineEdit("", list);
QLabel * url = new QLabel("", list);
QPushButton * removeLine = new QPushButton("remove", list);
//list is a QListWidget
QHBoxLayout * hbox = new QHBoxLayout;
hbox->addWidget(name);
hbox->addWidget(url);
hbox->addWidget(removeLine);
auto widget = new QWidget;
widget->setLayout(hbox);
auto item = new QListWidgetItem;
item->setSizeHint(QSize(0, 50));
list->addItem(item);
list->setItemWidget(item, widget);
connect(removeLine, &QPushButton::clicked,
[this, item]() {list->takeItem(list->row(item)); });

Using QTreeWidgetItems setData to store a QStackedWidget or QVariant

I am trying to make a QTreeWidget such that each row contains a series of comboboxes. Depending on how the user interacts with the comboboxes I would like certain comboboxes to becomes line edits and some to become buttons.
It was suggested here that a QStackedWidget would serve my needs and its done a pretty good job except now I need a way to alter the QStackedWidget that is next to the one that contains the combobox sending me an indexChanged signal. (Basically I want to change the neighboring QStackWidgets index)
I thought that I would be able to simply store the QStackWidget in the childItem using setData and then retrieve it inside the indexChanged slot but for some reason it appears the QStackWidget is not set to the childItems data.
Any help is appreciated.
This is where I orginally setup my QTreeWidget and its Items
QTreeWidgetItem *childItem = new QTreeWidgetItem(itemParent);
QVariant itemParentVariant,widgetParentVarient;
widgetParentVarient.setValue(widgetParent);
itemParentVariant.setValue(itemParent);
QList<QVariant> stackWidgetList;
uint cycleSetup;
for(cycleSetup = 0;cycleSetup < methodBlocks.at(rowType).size()+2;cycleSetup++)
{
QComboBox *itemComboBox = new QComboBox;
itemComboBox->setProperty("rowType", rowType);
itemComboBox->setProperty("row", 0);
itemComboBox->setProperty("column",cycleSetup);
itemComboBox->setProperty("widgetParent",widgetParentVarient);
itemComboBox->setProperty("itemParent",itemParentVariant);
itemComboBox->addItems(methodBlocks.at(0).at(cycleSetup));
QObject::connect(itemComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnComboIndexChanged(const QString&)));
QLineEdit *itemLineEdit = new QLineEdit;
QPushButton *itemButton = new QPushButton;
itemButton->setText("Reset");
QComboBox *timeComboBox = new QComboBox;
timeComboBox->setProperty("rowType", rowType);
timeComboBox->setProperty("row", 0);
timeComboBox->setProperty("column",cycleSetup);
timeComboBox->setProperty("widgetParent",widgetParentVarient);
timeComboBox->setProperty("itemParent",itemParentVariant);
timeComboBox->addItems(QString("Seconds;MilliSeconds;Reset").split(";"));
QStackedWidget *masterItemWidget = new QStackedWidget;
masterItemWidget->addWidget(itemLineEdit);
masterItemWidget->addWidget(itemComboBox);
masterItemWidget->addWidget(itemButton);
masterItemWidget->addWidget(timeComboBox);
masterItemWidget->setCurrentIndex(1);
QVariant stackParent;
stackParent.setValue(masterItemWidget);
itemComboBox->setProperty("stackParent",stackParent);
childItem->setData(0,Qt::UserRole,stackParent);
stackWidgetList.push_back(stackParent);
widgetParent->setItemWidget(childItem,cycleSetup,masterItemWidget);
itemParent->addChild(childItem);
}
And this is inside the slot where I am trying to retrieve the data (The QStackWidget)
QStackedWidget *itemMaster = combo->property("stackParent").value<QStackedWidget*>(); //this works
itemMaster->setCurrentIndex(0);
QTreeWidget *widgetParent = combo->property("widgetParent").value<QTreeWidget*>();
QTreeWidgetItem *parentItem = combo->property("itemParent").value<QTreeWidgetItem*>();
QTreeWidgetItem *childItem = new QTreeWidgetItem(parentItem);
QList<QVariant> stackList = childItem->data(0,Qt::UserRole).value<QList<QVariant>>(); //this doesnt
QStackedWidget *itemsibMaster = childItem->data(0,Qt::UserRole).value<QStackedWidget*>(); //neither does this
itemsibMaster->setCurrentIndex(2);
EDIT:
I've tried to set the data like this
QFrame *stackFrame = new QFrame;
QStackedWidget *masterItemWidget = new QStackedWidget(stackFrame);
masterItemWidget->addWidget(itemLineEdit);
masterItemWidget->addWidget(itemComboBox);
masterItemWidget->addWidget(itemButton);
masterItemWidget->addWidget(timeComboBox);
masterItemWidget->setCurrentIndex(1);
QVariant stackParent;
stackParent.setValue(masterItemWidget);
itemComboBox->setProperty("stackParent",stackParent);
QVariant frameVariant;
frameVariant.setValue(stackFrame);
childItem->setData(0,Qt::UserRole,frameVariant);
stackWidgetList.push_back(stackParent);
widgetParent->setItemWidget(childItem,cycleSetup,masterItemWidget);
itemParent->addChild(childItem);
And retrieve it like this
QStackedWidget *itemMaster = combo->property("stackParent").value<QStackedWidget*>();
itemMaster->setCurrentIndex(0);
QTreeWidget *widgetParent = combo->property("widgetParent").value<QTreeWidget*>();
QTreeWidgetItem *parentItem = combo->property("itemParent").value<QTreeWidgetItem*>();
QTreeWidgetItem *childItem = new QTreeWidgetItem(parentItem);
QFrame *frameObject = childItem->data(0,Qt::UserRole).value<QFrame*>();
//QList<QVariant> stackList = childItem->data(0,Qt::UserRole).value<QList<QVariant>>();
QStackedWidget *itemFrameMaster = frameObject->findChild<QStackedWidget*>();
if(itemFrameMaster)
{
qDebug() << "itemFrame Exists";
}
else
{
qDebug() << "itemFrame is NULL";//It goes to here
}
So I'm still unable to get the desired functionality.
Check if it works.
As stacked widget QStackedWidget derived from QFrame, Create a Frame object and add your stacked widget to it. Set the frame to your child item.
QFrame *stackFrame = new QFrame(Parent);
QStackedWidget *masterItemWidget = new QStackedWidget(stackFrame);
While querying first query for the frame and get the stacked widget child from it.
QStackedWidget *stackedWidget = FrameObject->findChild<QStackedWidget *>();
Alright so I managed to get the functionality that I was after, so in case anyone else is trying to do this here's the fix.
Essentially everything I had done before was correct except for one error.
When retrieving the data stored in the comboboxes child I had originally gotten that child here.
QTreeWidgetItem *parentItem = combo->property("itemParent").value<QTreeWidgetItem*>();
QTreeWidgetItem *childItem = new QTreeWidgetItem(parentItem);
The issue was that since the parentItem had more than one child (I suppose in this case the minimum is two children) I was not referencing the correct child. This issue was solved by creating a custom combobox property which held the child rather than the parent (parent can be derived from the parent more accurately than visa versa).
Now where I populate the QTreeWidget with combobox items looks like this.
QTreeWidgetItem *childItem = new QTreeWidgetItem(itemParent);
QVariant childItemVariant,widgetParentVarient;
widgetParentVarient.setValue(widgetParent);
childItemVariant.setValue(childItem);
uint cycleSetup;
for(cycleSetup = 0;cycleSetup < methodBlocks.at(rowType).size();cycleSetup++)
{
if(cycleSetup < methodBlocks.at(rowType).size())
{
QComboBox *itemComboBox = new QComboBox;
itemComboBox->setProperty("rowType", rowType);
itemComboBox->setProperty("row", 0);
itemComboBox->setProperty("column",cycleSetup);
itemComboBox->setProperty("widgetParent",widgetParentVarient);
itemComboBox->setProperty("childItem",childItemVariant);
itemComboBox->addItems(methodBlocks.at(0).at(cycleSetup));
QObject::connect(itemComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnComboIndexChanged(const QString&)));
QLineEdit *itemLineEdit = new QLineEdit;
QFrame *stackFrame = new QFrame;
QStackedWidget *masterItemWidget = new QStackedWidget(stackFrame);
masterItemWidget->addWidget(itemLineEdit);
masterItemWidget->addWidget(itemComboBox);
//masterItemWidget->addWidget(timeComboBox);
masterItemWidget->setCurrentIndex(1);
QVariant stackParent;
stackParent.setValue(masterItemWidget);
itemComboBox->setProperty("stackParent",stackParent);
itemComboBox->setProperty("cycleSetupIT",cycleSetup);
QVariant frameVariant;
frameVariant.setValue(stackFrame);
childItem->setData(cycleSetup,Qt::UserRole,stackParent);
widgetParent->setItemWidget(childItem,cycleSetup,masterItemWidget);
itemParent->addChild(childItem);
}
}
}
And the code in the slot where I get the data from the childItem (which holds the combobox) looks like this.
QTreeWidget *widgetParent = combo->property("widgetParent").value<QTreeWidget*>();
widgetParent->setColumnCount(6);
QTreeWidgetItem *childItem = combo->property("childItem").value<QTreeWidgetItem*>();
QTreeWidgetItem *parentItem = childItem->parent();
int rowType = combo->property("rowType").toInt();
int cycleIT = combo->property("cycleSetupIT").toInt();
int offset = 0;
QStackedWidget *itemFrameMaster = childItem->data(cycleIT+1,Qt::UserRole).value<QStackedWidget*>();
itemFrameMaster->setCurrentIndex(0);
Hope this helps. Also if anyone knows how to get the number of data items in a QStandardItem::data() that'd be great albeit not super critical.
Cheers!

Qt: How to set "?" button for a QWidget?

In a QWidget like QLabel, how can we set a "?" button, such that when clicked (or hovered) it should show some help text.
Also you can use QMenu instead of QPushButton + QLabel.
// Constructor
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotCustomMenu(QPoint)));
// slotCustomMenu(QPoint)
QMenu menu(this);
menu.addAction(this->toolTip());
menu.addAction(this->whatsThis());
menu.exec(QCursor::pos());
Easiest way to show help when hover QWidget: setToolTip(QString) and setToolTipDuration(int).
If you want a "?" button, just implement your own QWidget. Then via ui designer or directly in your code add QPushButton and QLabel on layout, and show your QLabel with help text in position of cursor when clicked(). Something like this:
{
// Constructor
...
m_mainLabel = new QLabel("Main text");
m_button = new QPushButton("?");
m_helpLabel = new QLabel("Help text");
connect(m_button, SIGNAL(clicked(bool)),
this, SLOT(slotShowOrHideHelpLabel(bool)));
QHBoxLayout *hBoxLayout = new QHBoxLayout;
hBoxLayout->addWidget(m_mainLabel);
hBoxLayout->addWidget(m_button);
setLayout(hBoxLayout);
}
void slotShowOrHideHelpLabel(bool showHelpLabel)
{
if (showHelpLabel)
{
m_helpLabel->show();
m_helpLabel->move(QCursor::pos());
}
else
{
m_helpLabel->hide();
}
}

Adding multiple QDockWidget's

I am able to add QDockWidgets as follows:
QDW1 QDW2;
QDW3 QDW4;
by using the code
QDockWidget *dwidget = new QDockWidget(tr("QDW1"), this);
addDockWidget(Qt::LeftDockWidgetArea, dwidget);
dwidget = new QDockWidget(tr("QDW2"), this);
dwidget->show();
addDockWidget(Qt::LeftDockWidgetArea, dwidget);
QDockWidget *dwidget2 = new QDockWidget(tr("QDW2"), this);
addDockWidget(Qt::RighttDockWidgetArea, dwidget2);
dwidget2 = new QDockWidget(tr("QDW4"), this);
dwidget2->show();
addDockWidget(Qt::RighttDockWidgetArea, dwidget2);
Now I want to add as follows:
I want to add total of 6 QDockWidgets
QDW1 QDW2 QDW3;
QDW4 QDW5 QDW6;
Can you please give me an idea how to add the dock widgets in this 2X3 format?
Thank you for the help.
HBS
This should do the trick :
QDockWidget *dwidget = new QDockWidget(tr("QDW1"), this);
addDockWidget(Qt::RightDockWidgetArea, dwidget);
QDockWidget *dwidget2 = new QDockWidget(tr("QDW2"), this);
splitDockWidget(dwidget, dwidget2, Qt::Horizontal);
QDockWidget *dwidget3 = new QDockWidget(tr("QDW3"), this);
addDockWidget(Qt::RightDockWidgetArea, dwidget3);
QDockWidget *dwidget4 = new QDockWidget(tr("QDW4"), this);
splitDockWidget(dwidget3, dwidget4, Qt::Horizontal);
QDockWidget *dwidget5 = new QDockWidget(tr("QDW5"), this);
addDockWidget(Qt::RightDockWidgetArea, dwidget5);
QDockWidget *dwidget6 = new QDockWidget(tr("QDW6"), this);
splitDockWidget(dwidget5, dwidget6, Qt::Horizontal);
This is a pretty easy answer, maybe I am missing something - couldn't you just add three each to the top and bottom DockWidgetArea?
How does your main widget / layout look like? Usually dockWidgets are not intended as the sole content, no?

How to fix QHBoxLayout items size and add drop-down list to every item in QHBoxLayout

I have custom window class
#define NAME_WIDTH 150
#define NAME_HEIGHT 20
ObjectWindow::ObjectWindow(QWidget * parent)
{
}
void ObjectWindow::SetKey(KeyObject * keyObj)
{
QGridLayout * layout = new QGridLayout(this);
nameField = new QTextEdit(this);
nameField->setText(keyObj->name);
nameField->setGeometry(nameField->geometry().x(), nameField->geometry().y(),
NAME_WIDTH, NAME_HEIGHT);
layout->addWidget(nameField);
QHBoxLayout * picsLayout = new QHBoxLayout(this);
for(std::vector<ImageInstance*>::iterator imgObj = keyObj->images.begin(); imgObj != keyObj->images.end(); imgObj++)
{
QComboBox * folderList = new QComboBox;
picsLayout->addWidget(folderList);
QImage image((*imgObj)->imgPath);
QLabel * picLabel = new QLabel;
picLabel->setPixmap(QPixmap::fromImage(image).scaled(200, 200, Qt::KeepAspectRatio, Qt::SmoothTransformation));
picsLayout->addWidget(picLabel);
}
layout->addLayout(picsLayout, 2, 0);
QPushButton * saveBtn = new QPushButton(this);
saveBtn->setText("Save");
connect(saveBtn, SIGNAL(released()),this, SLOT(Save()));
layout->addWidget(saveBtn);
setLayout(layout);
}
What i need is
small text field to set the name, I don't unerstand why SetGeometry doesn't work
dropdown list above each image. I can create QHVertical layout for each set of image and list, but maybe there is more simple way to do it?
If you just want the user to set the name, a QLineEdit is probably enough.
Then the main advantage of using a QGridLayout is that you don't need to create other layouts. It acts like a grid where you put your widgets, a bit like Excel (and other spreadsheet programs).
Oh and I see that you are not constructing the Widgets in the constructor (which seems to be empty), that's what people usually do because constructing the UI can be expensive and you just want to update it when relevant, not rebuilding the whole UI just to update a field. But without more code I cannot tell when this function is being called.
You can try something like this:
QGridLayout * layout = new QGridLayout(this);
nameField = new QLineEdit(this);
nameField->setText(keyObj->name);
layout->addWidget(nameField, 0, 0, -1, 1); // expand to the right edge
int currentColumn = 0;
for(std::vector<ImageInstance*>::iterator imgObj = keyObj->images.begin(); imgObj != keyObj->images.end(); imgObj++)
{
QComboBox * folderList = new QComboBox;
layout->addWidget(folderList, 1, currentColumn);
QPixmap pixmap((*imgObj)->imgPath);
pixmap = pixmap.scaled(200, 200, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QLabel * picLabel = new QLabel(this);
picLabel->setPixmap(pixmap);
layout->addWidget(picLabel, 2, currentColumn);
++currentColumn;
}
QPushButton * saveBtn = new QPushButton("Save", this);
connect(saveBtn, SIGNAL(released()),this, SLOT(Save()));
layout->addWidget(saveBtn, 3, 0, -1, 1);
setLayout(layout);
But it doesn't seem to be a good idea to add those widgets horizontally like that. What would happen if there are 100 items in this vector? You should investigate in using something like a QScrollArea or modifying the UI to give your client the best way to view and edit those (but without more context it seems difficult to give your more advice).