Qt - Centering a checkbox in a QTable - c++

In QtCreater I added a table to my project. in my code I am generating some data to output into the table. I want to add a QCheckbox into each row to allow the row to be selected. All the content of the table is aligned left, how do I make only these checkboxes in the first column of every row align to the center?
I'm adding the QCheckbox using:
ui->data_table->setCellWidget(rowCount,0, new QCheckBox);

Two thumbs up for Barry Mavin! You don't even have to subclass.
one line...
pCheckBox->setStyleSheet("margin-left:50%; margin-right:50%;");
done!!

I usually use a layout and a container widget for this. It is an ugly solution, but it works:
QWidget * w = new QWidget();
QHBoxLayout *l = new QHBoxLayout();
l->setAlignment( Qt::AlignCenter );
l->addWidget( <add your checkbox here> );
w->setLayout( l );
ui->data_table->setCellWidget(rowCount,0, w);
So basically you will have:
Table Cell -> Widget -> Layout -> Checkbox
you'll have to consider it if you will need to access the checkbox through the table.

This is an old post but in fact there is a much easier and lighter way of achieving this, just subclass QCheckBox and set the stylesheet to
margin-left:50%;
margin-right:50%;

It works for me, but my checkbox is not completely displayed.
To have a complete view of the widget, remove margins in layout :
l->setContentsMargins(0,0,0,0);

As stated in similar question around Stack Overflow, it's currently an open BUG:
https://bugreports.qt-project.org/browse/QTBUG-5368

can be center like this too using layout if want to add more customization
// Create a widget that will contain a checkbox
QWidget *checkBoxWidget = new QWidget();
QCheckBox *checkBox = new QCheckBox(); // We declare and initialize the checkbox
QHBoxLayout *layoutCheckBox = new QHBoxLayout(checkBoxWidget); // create a layer with reference to the widget
layoutCheckBox->addWidget(checkBox); // Set the checkbox in the layer
layoutCheckBox->setAlignment(Qt::AlignCenter); // Center the checkbox
layoutCheckBox->setContentsMargins(0,0,0,0); // Set the zero padding
ui->my_table_view->setCellWidget(row_number,column_number, checkBoxWidget); // set cell widget
OR simply add left right margins
checkBox->setStyleSheet("margin-left:50%; margin-right:50%;");

#if QT_VERSION < 0x046000
#include <QCommonStyle>
class MyStyle : public QCommonStyle {
public:
QRect subElementRect(SubElement subElement, const QStyleOption *option, const QWidget *widget = 0) const {
switch(subElement) {
case QStyle::SE_CheckBoxIndicator: {
QRect r = QCommonStyle::subElementRect(subElement, option, widget);
r.setRect( (widget->width() - r.width())/2, r.top(), r.width(), r.height());
return QRect(r);
}
default: return QCommonStyle::subElementRect(subElement, option, widget);
}
}
};
#else
#include <QProxyStyle>
#include <QStyleFactory>
class MyStyle: public QProxyStyle {
public:
MyStyle():QProxyStyle(QStyleFactory::create("Fusion")) {}
QRect subElementRect(SubElement subElement, const QStyleOption *option, const QWidget *widget = 0) const {
switch(subElement) {
case QStyle::SE_CheckBoxIndicator: {
QRect r = QProxyStyle::subElementRect(subElement, option, widget);
r.setRect( (widget->width() - r.width())/2, r.top(), r.width(), r.height());
return QRect(r);
}
default: return QProxyStyle::subElementRect(subElement, option, widget);
}
}
};
#endif
QCheckBox *box = new QCheckBox();
box->setStyle(new MyStyle());

Related

QListWidget drag and drop with a custom widget set via setItemWidget

I'm using a QListWidget to display custom widgets by setting them with setItemWidget. Something like this:
QListWidget* listWidget = new QListWidget;
listWidget->setAcceptDrops(true);
listWidget->setDragDropMode(QAbstractItemView::InternalMove);
listWidget->setDragEnabled(true);
listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
for ( int i = 0 ; i < 50 ; ++i )
{
ItemWidget* item = new ItemWidget;
QListWidgetItem* listItem = new QListWidgetItem;
listItem->setSizeHint(item->sizeHint());
listWidget->addItem(listItem);
listWidget->setItemWidget(listItem, item);
}
ItemWidget is derived from QWidget, and just displays some custom data in a layout, like this:
ItemWidget::ItemWidget()
{
QVBoxLayout* layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
QHBoxLayout* contentLayout = new QHBoxLayout;
contentLayout->setSizeConstraint(QLayout::SetFixedSize);
contentLayout->setSpacing(0);
contentLayout->addSpacing(5);
contentLayout->setContentsMargins(10, 20, 10, 20);
QLabel* iconLbl = new QLabel;
iconLbl->setPixmap(QPixmap(":/icon.png"));
iconLbl->setMaximumWidth(20);
contentLayout->addWidget(iconLbl, 0, Qt::AlignTop);
contentLayout->addSpacing(14);
QVBoxLayout* infoLayout = new QVBoxLayout;
infoLayout->setContentsMargins(0, 0, 0, 0);
infoLayout->setSpacing(0);
QLabel* firstLbl = new QLabel("First line of text");
infoLayout->addWidget(firstLbl);
infoLayout->addSpacing(4);
QLabel* secondLbl = new QLabel("Second line of text");
infoLayout->addWidget(secondLbl);
contentLayout->addLayout(infoLayout);
layout->addLayout(contentLayout);
setLayout(layout);
}
I'd like to implement drag & drop to be able to rearrange the items in the list. However, when using setItemWidget, when the mouse is dragging the item, only the background rectangle (the QListWidgetItem ?) is dragged around, with none of the custom content that's part of the ItemWidget showing. I'd like the item being dragged to include the ItemWidget content as well, so the user sees what's being dragged and dropped.
Does anyone have a working approach of implementing this?
I've already tried using a custom class derived from both QListWidgetItem and QWidget, and setting a custom layout directly in that class, thereby perhaps not needing an ItemWidget or using setItemWidget, but it didn't work out as I had hoped.
To customize the QPixmap associated with the QDrag of QListWidget we must override the startDrag() method.
The main task is to get a QPixmap of the elements selected for it is created a QPixmap the size of the visible image of the viewport() that is transparent and then we paint them with QPixmap of each item selected for it we use QPainter.
To obtain the QPixmap of each item, use the grab() method, indicating the rectangle obtained through visualRect().
#ifndef LISTWIDGET_H
#define LISTWIDGET_H
#include <QListWidget>
#include <QDrag>
#include <QMimeData>
#include <QPainter>
class ListWidget : public QListWidget
{
protected:
void startDrag(Qt::DropActions supportedActions){
QDrag *drag = new QDrag(this);
drag->setMimeData(model()->mimeData(selectedIndexes()));
QPixmap pixmap(viewport()->visibleRegion().boundingRect().size());
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
for(QModelIndex index: selectedIndexes()){
painter.drawPixmap(visualRect(index), viewport()->grab(visualRect(index)));
}
drag->setPixmap(pixmap);
drag->setHotSpot(viewport()->mapFromGlobal(QCursor::pos()));
drag->exec(supportedActions, Qt::MoveAction);
}
};
#endif // LISTWIDGET_H
The complete example can be found in the following link

how to align center align a radio button inside a qtable widget? [duplicate]

In QtCreater I added a table to my project. in my code I am generating some data to output into the table. I want to add a QCheckbox into each row to allow the row to be selected. All the content of the table is aligned left, how do I make only these checkboxes in the first column of every row align to the center?
I'm adding the QCheckbox using:
ui->data_table->setCellWidget(rowCount,0, new QCheckBox);
Two thumbs up for Barry Mavin! You don't even have to subclass.
one line...
pCheckBox->setStyleSheet("margin-left:50%; margin-right:50%;");
done!!
I usually use a layout and a container widget for this. It is an ugly solution, but it works:
QWidget * w = new QWidget();
QHBoxLayout *l = new QHBoxLayout();
l->setAlignment( Qt::AlignCenter );
l->addWidget( <add your checkbox here> );
w->setLayout( l );
ui->data_table->setCellWidget(rowCount,0, w);
So basically you will have:
Table Cell -> Widget -> Layout -> Checkbox
you'll have to consider it if you will need to access the checkbox through the table.
This is an old post but in fact there is a much easier and lighter way of achieving this, just subclass QCheckBox and set the stylesheet to
margin-left:50%;
margin-right:50%;
It works for me, but my checkbox is not completely displayed.
To have a complete view of the widget, remove margins in layout :
l->setContentsMargins(0,0,0,0);
As stated in similar question around Stack Overflow, it's currently an open BUG:
https://bugreports.qt-project.org/browse/QTBUG-5368
can be center like this too using layout if want to add more customization
// Create a widget that will contain a checkbox
QWidget *checkBoxWidget = new QWidget();
QCheckBox *checkBox = new QCheckBox(); // We declare and initialize the checkbox
QHBoxLayout *layoutCheckBox = new QHBoxLayout(checkBoxWidget); // create a layer with reference to the widget
layoutCheckBox->addWidget(checkBox); // Set the checkbox in the layer
layoutCheckBox->setAlignment(Qt::AlignCenter); // Center the checkbox
layoutCheckBox->setContentsMargins(0,0,0,0); // Set the zero padding
ui->my_table_view->setCellWidget(row_number,column_number, checkBoxWidget); // set cell widget
OR simply add left right margins
checkBox->setStyleSheet("margin-left:50%; margin-right:50%;");
#if QT_VERSION < 0x046000
#include <QCommonStyle>
class MyStyle : public QCommonStyle {
public:
QRect subElementRect(SubElement subElement, const QStyleOption *option, const QWidget *widget = 0) const {
switch(subElement) {
case QStyle::SE_CheckBoxIndicator: {
QRect r = QCommonStyle::subElementRect(subElement, option, widget);
r.setRect( (widget->width() - r.width())/2, r.top(), r.width(), r.height());
return QRect(r);
}
default: return QCommonStyle::subElementRect(subElement, option, widget);
}
}
};
#else
#include <QProxyStyle>
#include <QStyleFactory>
class MyStyle: public QProxyStyle {
public:
MyStyle():QProxyStyle(QStyleFactory::create("Fusion")) {}
QRect subElementRect(SubElement subElement, const QStyleOption *option, const QWidget *widget = 0) const {
switch(subElement) {
case QStyle::SE_CheckBoxIndicator: {
QRect r = QProxyStyle::subElementRect(subElement, option, widget);
r.setRect( (widget->width() - r.width())/2, r.top(), r.width(), r.height());
return QRect(r);
}
default: return QProxyStyle::subElementRect(subElement, option, widget);
}
}
};
#endif
QCheckBox *box = new QCheckBox();
box->setStyle(new MyStyle());

QListWidgetItem - adjust width and height to content

I have got a QListWidgetItem, which has a QWidget and some QLabels. The height of the labels (imageLabel, titleLabel and descriptionLabel) varies depending on the text length. So does the height of the QWidget, which leds to different sizes in QListWidgetItem. So far the parameters for setSizeHint are static:
QListWidgetItem* listWidgetItem = new QListWidgetItem();
listWidgetItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
listWidgetItem->setSizeHint(200, 180));
QWidget* widget = new QWidget();
QVBoxLayout* rootLayout = new QVBoxLayout();
rootLayout->setAlignment(Qt::AlignTop);
QHBoxLayout* contentLayout = new QHBoxLayout();
contentLayout->setAlignment(Qt::AlignLeft);
QLabel* imageLabel = new QLabel();
imageLabel->setPixmap(pixmap);
contentLayout->addWidget(imageLabel, 0, Qt::AlignTop);
QVBoxLayout* informationLayout = new QVBoxLayout();
informationLayout->setAlignment(Qt::AlignTop);
QLabel* titleLabel = new QLabel("<b>" + title + "</b>");
titleLabel->setWordWrap(true);
informationLayout->addWidget(titleLabel);
QLabel* descriptionLabel = new QLabel(description);
descriptionLabel->setWordWrap(true);
informationLayout->addWidget(descriptionLabel);
QLabel* dateLabel = new QLabel(date.toString());
informationLayout->addWidget(dateLabel);
contentLayout->addLayout(informationLayout);
rootLayout->addLayout(contentLayout);
QHBoxLayout* buttonLayout = new QHBoxLayout();
QPushButton* buttonOne = new QPushButton(tr("Button 1"));
QObject::connect(buttonOne, SIGNAL(clicked()), mButtonOneSignalMapper, SLOT(map()));
mButtonOneSignalMapper->setMapping(buttonOne, index);
buttonLayout->addWidget(buttonOne);
QPushButton* buttonTwo = new QPushButton(tr("Button 2"));
QObject::connect(buttonTwo, SIGNAL(clicked()), mButtonTwoSignalMapper, SLOT(map()));
mButtonTwoSignalMapper->setMapping(buttonTwo, index);
buttonLayout->addWidget(buttonTwo);
rootLayout->addLayout(buttonLayout);
widget->setLayout(rootLayout);
mListWidget->addItem(listWidgetItem);
mListWidget->setItemWidget(listWidgetItem, widget);
Is there any way to properly set the sizeHint regarding the width and height of the displayed content used in the QLabels of the QWidget?
For instance the first QListWidgetItem may have a descriptionLabel with a text length of 300 characters and the second QListWidgetItem may have a descriptionLabel with a text length of 1000 characters. So far both QListWidgetItems will have the same size (200px width and 180px height). While it may fit on the first QListWidgetItem, because it has only 300 characters, it may not fit on the second QListWidgetItem, because of the 1000 characters. Therefore I would like to somehow dynamically adjust the size of the QListWidgetItem regarding the needed space (first one will need less than the second one).
The way I see it, you won't be able to get a correct bounding rect for the label, unless you know it's future width, so that you can calculate the number of lines required to display the content. And you won't get the width before the layout with the other widgets is calculated.
An alternate approach might be to use an item delegate. Its sizeHint method has an option parameter with a preliminary rect, from which you can use the width and calculate the height with font metrics.
Concerning your other widgets, you could switch to a QTableWidget and put them in other columns..
The following code is not a working example .. just some clues to get you started..
class ItemDelegate : public QStyledItemDelegate
{
public:
void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
painter->save();
QStyledItemDelegate::paint(painter,option,index);
QString title = index.data(Qt::UserRole).toString();
QFont f = option.font;
painter->setFont(f);
QFontMetrics fm(f);
QRect r = option.rect;
// r = r.adjusted(0, fm.lineSpacing(), 0, 0);
painter->drawText(r.left(), r.top(), r.width(), r.height(), Qt::AlignTop|Qt::AlignLeft|Qt::TextWordWrap, title, &r);
painter->restore();
}
QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
QFont f = option.font;
QRect r = option.rect;
QFontMetrics fm(f);
QString title = index.data(Qt::UserRole).toString();
QRect br = fm.boundingRect(r,Qt::AlignTop|Qt::AlignLeft | Qt::TextWordWrap,title);
return QSize(option.rect.width(),br.height());
}
};
Hope it helps,
Johannes

QItemDelegate with custom widgets

I'm having problems with my QTableView and QItemDelegate classes. For one column my delegate creates a simple combo box and everything works just fine. For my 2nd column I need a widget that has two combo boxes in a single widget.
I've written the following code in my QItemDelegate, just to be clear this only shows code for my 2nd column, the one that doesn't work. The other simple Combo-box isn't shown as it works fine:
QWidget *UserDefinedUnitsDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem & option ,const QModelIndex & index ) const
{
//set up a simple widget with a layout
QWidget* pWidget = new QWidget(parent);
QHBoxLayout* hLayout = new QHBoxLayout(pWidget);
pWidget->setLayout(hLayout);
//add two combo boxes to the layout
QComboBox* comboEditor = new QComboBox(pWidget);
QComboBox* comboEditor2 = new QComboBox(pWidget);
//now add both editors to this
hLayout->addWidget(comboEditor);
hLayout->addWidget(comboEditor2);
return pWidget;
}
Now this displays just fine but when I edit it and click elsewhere it doesn't stop editing. Can anyone offer any pointers?
Edit: So i need to call CommitData() and closeEditor() at some point. Can anyone offer pointers on where to call these?
Thanks.
You can keep the editor widget as a member of class and emit commitData when the current index of one of the comboboxes has changed. So you can connect currentIndexChanged(int) to a slot and emit commitData from there:
QWidget *UserDefinedUnitsDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem & option ,const QModelIndex & index ) const
{
//set up a simple widget with a layout
pWidget = new QWidget(parent);
QHBoxLayout* hLayout = new QHBoxLayout(pWidget);
pWidget->setLayout(hLayout);
//add two combo boxes to the layout
QComboBox* comboEditor = new QComboBox(pWidget);
QComboBox* comboEditor2 = new QComboBox(pWidget);
connect(comboEditor,SIGNAL(currentIndexChanged(int)),this,SLOT(setData(int)));
connect(comboEditor2,SIGNAL(currentIndexChanged(int)),this,SLOT(setData(int)));
//now add both editors to this
hLayout->addWidget(comboEditor);
hLayout->addWidget(comboEditor2);
return pWidget;
}
void UserDefinedUnitsDelegate::setData(int val)
{
emit commitData(pWidget);
}

How can I add a checkbox/radio button to QTableWidget

How can I add a checkbox/radiobutton/combobox to a QTableWidget or a QListWidget?
There are two methods:
void QTableWidget::setCellWidget(int row, int column, QWidget* widget)
and
void QListWidget::setItemWidget(QListWidgetItem* item, QWidget* widget)
They allow to insert any widget and other controls that inherit QWidget. Checkbox/radio button/combobox do inherit from QWidget.
For a checkbox using the item's setCheckState method should do what you need both for list and table widgets. See if code below would work for you:
List widget:
QListWidgetItem *item0 = new QListWidgetItem(tr("First"), listWidget);
QListWidgetItem *item1 = new QListWidgetItem(tr("Second"), listWidget);
item0->setCheckState(Qt::Unchecked);
item1->setCheckState(Qt::Checked);
Table widget:
QTableWidgetItem *item2 = new QTableWidgetItem("Item2");
item2->setCheckState(Qt::Checked);
tableWidget->setItem(0, 0, item2);
You can use delegates (QItemDelegate) for other types of editor's widgets, example is here: Spin Box Delegate Example.
I hope this helps.
you can add checkbox like this too
#include <QCheckBox>
void addCheckBoxAt(int row_number, int column_number,int state)
{
// Create a widget that will contain a checkbox
QWidget *checkBoxWidget = new QWidget();
QCheckBox *checkBox = new QCheckBox(); // We declare and initialize the checkbox
QHBoxLayout *layoutCheckBox = new QHBoxLayout(checkBoxWidget); // create a layer with reference to the widget
layoutCheckBox->addWidget(checkBox); // Set the checkbox in the layer
layoutCheckBox->setAlignment(Qt::AlignCenter); // Center the checkbox
layoutCheckBox->setContentsMargins(0,0,0,0); // Set the zero padding
/* Check on the status of odd if an odd device,
* exhibiting state of the checkbox in the Checked, Unchecked otherwise
* */
if(state == 1){
checkBox->setChecked(true);
} else {
checkBox->setChecked(false);
}
ui->job_table_view->setCellWidget(row_number,column_number, checkBoxWidget);
// Another way to add check box as item
/*
// QTableWidgetItem *checkBoxItem = new QTableWidgetItem("checkbox string ");
QTableWidgetItem *checkBoxItem = new QTableWidgetItem();
checkBoxItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
checkBoxItem->setCheckState(Qt::Checked);
ui->job_table_view->setItem(row_number,column_number,checkBoxItem);
*/
}
// call it like
addCheckBoxAt(0,0,1); // insert checkbox it 0,0 and check status true