Is it possible to change default behavior of a checkable QGroupBox? - qt

The question is pretty straight forward: is it possible to change the default behavior of a checkable QGroupBox object? I designed a user interface with many QLineEdit objects inside a checkable QGroupBox, the desired behavior is: when QGroupBox is not checked all of its children are enable and when it is checked all of its children are disable.
As you can see at the oficial QGroupBox documentation, it says:
If the check box is checked, the group box's children are enabled; otherwise, the children are disabled and are inaccessible to the user.

One trick is to modify the painting so that when it is checked the check is not shown and vice versa:
#include <QtWidgets>
class GroupBox: public QGroupBox{
public:
using QGroupBox::QGroupBox;
protected:
void paintEvent(QPaintEvent *){
QStylePainter paint(this);
QStyleOptionGroupBox option;
initStyleOption(&option);
if(isCheckable()){
option.state &= ~(isChecked() ? QStyle::State_On : QStyle::State_Off);
option.state |= (isChecked() ? QStyle::State_Off : QStyle::State_On);
}
paint.drawComplexControl(QStyle::CC_GroupBox, option);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GroupBox groupBox;
groupBox.setCheckable(true);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(new QLineEdit);
vbox->addWidget(new QLineEdit);
vbox->addWidget(new QLineEdit);
vbox->addStretch(1);
groupBox.setLayout(vbox);
groupBox.show();
return a.exec();
}

Related

QEvent::Drop event is never generated for QQuickView window

I'm struggling with an issue that QEvent::Drop event is never generated for my QQuickView window.
I need to implement a drag'n'drop functionality, to drop files from explorer to the QQuickView.
As described in this post, i've istalled an eventfilter for the QQuickView objet, and in eventFilter() method trying to catch required events. The QEvent::DragMove is being generated as expected, as i drag a file over the view. But when i drop the file on the view, the QEvent::Drop is not being generated. Instead, the QEvent::DragLeave is generated.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
Filter f;
QQuickView *view = new QQuickView;
view->installEventFilter(&f);
view->show();
return a.exec();
}
And here is a (Event)Filter class code:
(header)
class Filter : public QObject
{
Q_OBJECT
public:
Filter(){};
virtual bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE;
};
(source)
bool Filter::eventFilter(QObject *watched, QEvent *event)
{
if(event->type() == QEvent::DragMove)
qDebug() << "it's a drag";
if(event->type() == QEvent::Drop)
qDebug() << "it's a drop"; // <<-- Never reaches here
return QObject::eventFilter(watched, event);
}
My colleagues helped me out with this question.
Apparently you have to add a DropArea item to your QML root file, and after that the QQuickView will start receiving QEvent::Drop events.
I can not find any documentation on this case though, and i also wonder what would be more general solution for this, if you had a QWindow class instead.
Anyway, I'm closing this question.

Disable specific items in QComboBox

In my application, I want to disable some items (i.e. not selectable, no highlights when mouse hovering above, and the texts are greyed out) in the QComboBox when certain conditions are met.
I indeed found someone did ask the same question here: Disable Item in Qt Combobox
But none of these solutions in the answers seem to actually work (including the trick).
Is there a decent and 'correct' way to implement this?
EDIT:
I found out why setting the flags wouldn't disable the items in my application: for some reasons, I had to set the style QStyle::SH_ComboBox_UseNativePopup(see https://codereview.qt-project.org/#/c/82718/). And this setting for some reasons blocked the flag setting. Does anyone have an idea why, and how to work around? A minimum test example is included (modified from the answer of #Mike):
#include <QApplication>
#include <QComboBox>
#include <QStandardItemModel>
#include <QProxyStyle>
class ComboBoxStyle : public QProxyStyle
{
public:
int styleHint ( StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, QStyleHintReturn * returnData = 0 ) const override
{
if ( hint == QStyle::SH_ComboBox_UseNativePopup )
{
return 1;
}
return QProxyStyle::styleHint( hint, option, widget, returnData );
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QComboBox comboBox;
// Setting this style would block the flag settings later on.
comboBox.setStyle( new ComboBoxStyle() );
comboBox.insertItem(0, QObject::tr("item1"));
comboBox.insertItem(1, QObject::tr("item2"));
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(comboBox.model());
QStandardItem* item= model->item(1);
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
comboBox.show();
return a.exec();
}
The answer linked in my comment above seems to be talking about an old version of Qt. I have tested on Qt5.4 and Qt5.6 and there is no need set the color yourself here, you just need to set and/or clear the Qt::ItemIsEnabled flag, here is an example:
#include <QtWidgets>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QComboBox comboBox;
comboBox.addItem(QObject::tr("item1"));
comboBox.addItem(QObject::tr("item2"));
comboBox.addItem(QObject::tr("item3"));
QStandardItemModel *model =
qobject_cast<QStandardItemModel *>(comboBox.model());
Q_ASSERT(model != nullptr);
bool disabled = true;
QStandardItem *item = model->item(2);
item->setFlags(disabled ? item->flags() & ~Qt::ItemIsEnabled
: item->flags() | Qt::ItemIsEnabled);
comboBox.show();
return a.exec();
}
Here is the technique #Mike describes, wrapped up in a convenient utility function:
void SetComboBoxItemEnabled(QComboBox * comboBox, int index, bool enabled)
{
auto * model = qobject_cast<QStandardItemModel*>(comboBox->model());
assert(model);
if(!model) return;
auto * item = model->item(index);
assert(item);
if(!item) return;
item->setEnabled(enabled);
}

Disable validation in QSpinBox

Hence I have a QSpinBox, and want to unset validation for writing not only int values, but also string in it.
Please help me to fix this.
I have tried this, but it does not work:
class Spinbox:public QSpinBox
{
public:
Spinbox(QWidget* parent=0)
:QSpinBox(parent){}
void setLineEdit(QLineEdit *l)
{
QSpinBox::setLineEdit(l);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Spinbox de;
QLineEdit le;
le.setValidator(0);
le.setText("text");
de.setLineEdit(&le);
de.show();
return a.exec();
}
Qt docs say that:
If QLineEdit::validator() for the lineEdit returns 0, the internal
validator of the spinbox will be set on the line edit.
Thus, in order to disable the QSpinBox's built in validator, you need to set your own (dummy?). I.e.
class Validator : public QValidator
{
public:
State validate(QString &input, int &pos ) const
{
return QValidator::Acceptable;
}
};
[..]
Spinbox de;
QLineEdit le;
le.setValidator(new Validator());
le.setText("text");
de.setLineEdit(&le);
de.show();

QListView show text when list is empty

I want to show some text (like "No items") when there are no items in QListView.
I tried to override paintEvent method of QListView, but it doesn't have any effect.
The code below shows a simple way of doing it by overloading the paintEvent method of the view. Painting of the text should probably use the style mechanism to obtain the font and pen/brush, but I'll leave that up for grabs by a keen editor.
It uses Qt 5 and its C++11 features, doing it the Qt 4 or pre-C++11 way would require a QObject-deriving class with a slot to connect to the spin box's valueChanged signal. The implementation of ListView doesn't need to change between Qt 4 and Qt 5.
#include <QtWidgets>
class ListView : public QListView {
void paintEvent(QPaintEvent *e) {
QListView::paintEvent(e);
if (model() && model()->rowCount(rootIndex()) > 0) return;
// The view is empty.
QPainter p(this->viewport());
p.drawText(rect(), Qt::AlignCenter, "No Items");
}
public:
ListView(QWidget* parent = 0) : QListView(parent) {}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QFormLayout layout(&window);
ListView view;
QSpinBox spin;
QStringListModel model;
layout.addRow(&view);
layout.addRow("Item Count", &spin);
QObject::connect(&spin, (void (QSpinBox::*)(int))&QSpinBox::valueChanged,
[&](int value){
QStringList list;
for (int i = 0; i < value; ++i) list << QString("Item %1").arg(i);
model.setStringList(list);
});
view.setModel(&model);
window.show();
return a.exec();
}
If you use a QListView, you probably have a custom model containing data you want to display. This is maybe the best place to returns "No items" when your model is empty.

Can not set font-weight for pseudo-states in qt

I'm facing a problem in which I want to make the font bold in an QPushButton when it is hovered or pressed. But font-weight property only works in normal state, on font state it doesn't affect anything.
I'm really looking for a solution.
Looks like a bug to me--the style sheet font properties are ignored in the hover state. I was not able to come up with a workaround using style sheets, but you can always subclass QPushButton to get what you need:
#include <QtGui>
class HoverablePushButton : public QPushButton {
public:
HoverablePushButton(const QString &text, QWidget *parent = NULL)
: QPushButton(text, parent) {}
protected:
void enterEvent(QEvent *event) {
QPushButton::enterEvent(event);
QFont f(font());
f.setBold(true);
setFont(f);
}
void leaveEvent(QEvent *event) {
QPushButton::leaveEvent(event);
QFont f(font());
f.setBold(false);
setFont(f);
}
};
int main(int argc, char **argv) {
QApplication app(argc, argv);
HoverablePushButton b("hello!");
b.show();
return app.exec();
}
Might be overkill, but if the functionality is critical for your application, it is at least one workaround.

Resources