Toggling a checkbox inside a QComboBox - c++

I'm displaying checkboxes inside comboboxes using an adaptation of the following code. Unfortunately, the checkboxes do not behave exactly as expected. In contrast to a "normal" checkbox one can not click the checkbox's label to (un-)check the checkbox.
Is there a way to make the checkboxes inside the comboboxes behave exactly like a "normal" checkbox (i.e. clicking on the label (un-)checks it)?
#include <QtGui>
#include <QApplication>
#include <QComboBox>
#include <QTableView>
#include <QVBoxLayout>
#include <QListView>
#include <QCheckBox>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QStandardItemModel model;
QList<QStandardItem*> items;
for (int i = 0; i < 5; i++) {
QStandardItem* item = new QStandardItem(QString("Item %0").arg(i));
item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
item->setData(Qt::Unchecked, Qt::CheckStateRole);
items.append(item);
}
model.appendColumn(items);
QComboBox* comboBox = new QComboBox();
comboBox->setModel(&model);
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(comboBox);
layout->addWidget(new QCheckBox("Label"));
QWidget widget;
widget.setLayout(layout);
widget.show();
return app.exec();
}

No, you can not do that directly. However you can explicitly specify the behaviour of the label once it's clicked. Not to copy the code from another question, you can do something like in this question.

Related

Qt QScrollArea leftover graphic artifacts when scrolling with TranslucentBackground flag

I get graphic artifacts when scrolling a qscrollarea that is not a seperate window and both the scroll area and the target widget's TranslucentBackground flag is set to true. The problem doesn't happen when the scrollarea is opened as a seperate window with null parent or Qt::Window flag.
Was this behavior intended or is this a bug?
If it is a bug, is
there a fix you know of?
I've tried many other window flags but all the ones that don't open a separate window have the same issue.
#include <QApplication>
#include <QWidget>
#include <QHBoxLayout>
#include <QPushButton>
#include <QScrollArea>
#include <QScrollerProperties>
#include <QScroller>
#include <QTouchDevice>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *mainWindow = new QWidget;
QHBoxLayout *buttonsLayout = new QHBoxLayout;
QWidget *buttonsWidget = new QWidget();
buttonsWidget->setLayout(buttonsLayout);
buttonsWidget->setAttribute(Qt::WA_TranslucentBackground);
buttonsWidget->setAttribute(Qt::WA_NoSystemBackground);
for(int i = 0; i < 10; ++i) {
QPushButton *button = new QPushButton("Button " + QString::number(i), buttonsWidget);
buttonsLayout->addWidget(button);
}
QScrollArea *scrollArea = new QScrollArea(mainWindow);
scrollArea->setAttribute(Qt::WA_TranslucentBackground);
scrollArea->setAttribute(Qt::WA_NoSystemBackground);
scrollArea->setWidgetResizable(true);
scrollArea->setFixedHeight(100);
scrollArea->setWidget(buttonsWidget);
scrollArea->setWindowFlag(Qt::WindowStaysOnTopHint);
mainWindow->show();
scrollArea->show();
return a.exec();
}
Example artifact when, compiled with Qt5.12.1 open source version, ubuntu 16.04.

How do I make a QTreeView fill the whole dialog and resize with it?

I have a QTreeView and I can't find a way of making it fill the whole dialog window and resize with the window when it is resized.
Something like this:
#include <QApplication>
#include <QDialog>
#include <QHBoxLayout>
#include <QTreeView>
class MyDialog: public QDialog
{
public:
MyDialog()
{
QHBoxLayout* l = new QHBoxLayout(this);
setLayout(l);
QTreeView* v = new QTreeView(this);
l->addWidget(v);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyDialog d;
d.exec();
return a.exec();
}

Display text from QLineEdit in a QTextEdit already containing some text and update it in real time

What is the procedure to make a text being written in a QLineEdit widget, dynamically display inside a QTextEdit that already contains some text?
For example, let us say that a QLineEdit asks for a name where one writes "John". Is it possible to display it in real time inside a QTextEdit containing :
The name is + textFromQLineEdit + , age 24 ?
The displayed text has to dynamically take into account the changes being made to the QLineEdit so that the user does not need to press a button or press enter to see his/her name appear.
The following is the minimal code for connecting the two widgets to each other using the signal textChanged() from QLineEdit and the slot setText() from QTextEdit (which does not allow for adding some text before and after the text from the QLineEdit) :
#include <QLineEdit>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QTextEdit>
#include <QApplication>
class SmallWindow : public QWidget
{
Q_OBJECT
public:
SmallWindow();
private:
QLineEdit *nameLine;
QTextEdit *textBox;
};
SmallWindow::SmallWindow() : QWidget()
{
setFixedSize(300,250);
QLineEdit *nameLine = new QLineEdit;
QTextEdit *textBox = new QTextEdit;
QWidget::connect(nameLine,SIGNAL(textChanged(QString)),textBox,SLOT(setText(QString)));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(nameLine);
layout->addWidget(textBox);
QGroupBox *group = new QGroupBox(this);
group->setLayout(layout);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
SmallWindow window;
window.show();
app.exec();
}
#include "main.moc"
What should be done to keep the text before and after the QLineEdit text in place and updating the QTextEdit box in real time?
Create special slot:
void SmallWindow::pasteText(const QString& str)
{
textBox->setText(QString("The name is %1 , age 24").arg(str));
}
and don't use textChanged() signal because you need only one name accepted by user, so you need QLineEdit::editingFinished() (or maybe QLineEdit::returnPressed(), it depends on your needs)
connect(nameLine,SIGNAL(editingFinished(QString)),this,SLOT(pasteText(QString)));
Also you don't need QWidget::connect, because you write this code inside QObject subclass, so it is not necessary.
Also these lines:
QLineEdit *nameLine = new QLineEdit;
QTextEdit *textBox = new QTextEdit;
should be:
nameLine = new QLineEdit;
textBox = new QTextEdit;
Create an own slot for the text update. I think that you have also some errors in your code.
Widgets nameLine and textBox are already defined in the SmallWindow.h. You probably want to create them in SmallWindow.cpp following way:
nameLine = new QLineEdit;
textBox = new QTextEdit;
Also GroupBox group is not set to any layouts. Perhaps you want to create one layout more and set the widget there?
QVBoxLayout *mainlayout = new QVBoxLayout;
mainlayout->addWidget(group);
this->setLayout(mainlayout);
If you create an own slot for the text update, you can just change text content of the textBox there:
SmallWindow.h
#ifndef SMALLWINDOW_H
#define SMALLWINDOW_H
#include <QLineEdit>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QTextEdit>
class SmallWindow : public QWidget
{
Q_OBJECT
public:
SmallWindow();
private slots:
void updateLineEditText(QString name);
private:
QLineEdit *nameLine;
QTextEdit *textBox;
};
#endif // SMALLWINDOW_H
SmallWindow.cpp
#include "SmallWindow.h"
SmallWindow::SmallWindow() : QWidget()
{
setFixedSize(300,250);
nameLine = new QLineEdit;
textBox = new QTextEdit;
connect(nameLine,SIGNAL(textChanged(QString)),this,
SLOT(updateLineEditText(QString)));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(nameLine);
layout->addWidget(textBox);
QGroupBox *group = new QGroupBox(this);
group->setLayout(layout);
QVBoxLayout *mainlayout = new QVBoxLayout;
mainlayout->addWidget(group);
this->setLayout(mainlayout);
}
void SmallWindow::updateLineEditText(QString name) {
QString textEditString("The name is ");
textEditString.append(name);
textEditString.append(", age 24 ?");
textBox->setText(textEditString);
}
This is a minimal example in Qt 5, using C++11. It is about as concise as it would be in Python. If you are using Qt 5, then your question should have looked exactly as it does below, save for the connect statement. This is what "minimal" means when it comes to Qt. Avoid the fluff and boilerplate that doesn't add to the problem. There's no need to have a separate class for the window in such a simple example.
#include <QVBoxLayout>
#include <QLineEdit>
#include <QTextEdit>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget window;
QVBoxLayout layout(&window);
QLineEdit name;
QTextEdit text;
layout.addWidget(&name);
layout.addWidget(&text);
QObject::connect(&name, &QLineEdit::textChanged, [&](const QString & name){
text.setPlainText(QString("The name is %1, age 24.").arg(name));
});
window.show();
return app.exec();
}
The same in Qt 4 is below - note the absence of any manual memory management. That's how your question ideally should have looked for Qt 4, without the slot's implementation of course. You can use the connectSlotsByName or an explicit connect, of course - that's just a matter of style.
#include <QVBoxLayout>
#include <QLineEdit>
#include <QTextEdit>
#include <QApplication>
class Window : public QWidget {
Q_OBJECT
QVBoxLayout m_layout; // not a pointer!
QLineEdit m_name; // not a pointer, must come after the layout!
QTextEdit m_text;
Q_SLOT void on_name_textChanged(const QString & name) {
m_text.setPlainText(QString("The name is %1, age 24.").arg(name));
}
public:
Window() : m_layout(this) {
m_layout.addWidget(&m_name);
m_layout.addWidget(&m_text);
m_name.setObjectName("name");
QMetaObject::connectSlotsByName(this);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Window window;
window.show();
return app.exec();
}
#include "main.moc"

Creating and laying out widgets using a for loop in Qt

So i wanted to create 5 buttons in Qt but instead, create just one button and put it in a for loop so i don't have to create each of the 5 buttons manually. I tried different ways but all proved futile. I'm new to C++ and Qt.
Here are the codes;
show.h
#ifndef SHOW_H
#define SHOW_H
#include <QDialog>
#include <QPushButton>
#include <QVBoxLayout>
class Show : public QDialog {
Q_OBJECT
public:
explicit Show(QWidget *parent = 0);
~Show();
private:
QPushButton *button;
};
#endif // SHOW_H
show.cpp
#include "show.h"
#include "ui_show.h"
Show::Show(QWidget *parent) : QDialog(parent) {
int a = 5;
button = new QPushButton[a];
button->setText("Ok");
QVBoxLayout *layout = new QVBoxLayout[a];
for (int i = 0; i < sizeof(button)/4; i++) {
/*here, i wanted to do something like this;
'layout[i].addWidget(button[i]);' but didn't work*/
layout[i].addWidget(button);
}
setLayout(layout);
}
Show::~Show() {
}
main.cpp
#include "show.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Show *dialog = new Show;
dialog->show();
return a.exec();
}
After i run the code, i only see one button.
Your help is deeply appreciated. Thank you!!
QPushButton* pButton = new QPushButton("Ok");
This creates a single instance of a QPushButton.
You can add the button to a layout with a call to Layout::addWidget, which internally calls addItem.
As the documentation states for addItem: -
Note: The ownership of item is transferred to the layout, and it's the layout's responsibility to delete it
So your current code creates a single button and as it gets added to each successive layout, it is removed from the layout in which it was previously added.
You're creating one button and adding the same button 5 times. If you want 5 buttons in 5 layouts using a loop, then you need 5 separate instances of the button: -
for (int i=0; i<5; ++i)
{
QPushButton* pButton = new QPushButton("Ok");
layout[i].addWidget(pButton);
}
In your show.cpp change the lines
Show::Show(QWidget *parent) : QDialog(parent) {
int a = 5;
// You only need one layout for all buttons, not one per button.
QVBoxLayout *layout = new QVBoxLayout( this );
for (int i = 0; i < a; i++) {
QPushButton * newButton = new QPushButton( this );
newButton ->setText( "Ok" );
layout->addWidget( newButton );
}
setLayout(layout);
}
Show::~Show() {
}
The layout expects a pointer and you only need one layout instead one per button.

Cannot press QPushButton in a simple program

Basically, I want a simple pushButton with a colorful text which when pressed exits the application.
Why cant I press PushButton in this simple program. I am using QT 4.6 on Arch x86_64.
#include <QtGui/QApplication>
#include <QLabel>
#include <QPushButton>
#include<QtGui>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow *Main=new QMainWindow;
QPushButton *button = new QPushButton(Main);
QLabel *label = new QLabel(Main);
label->setText("<h2><i>Hello</i> ""<font color=red>Qt!</font></h2>");
label->setVisible(true);
QObject::connect(button, SIGNAL(clicked()),label, SLOT(close()));
label->setAlignment(Qt::AlignCenter|Qt::AlignVCenter);
label->setWindowTitle("HelloWorld Test Program");
Main->show();
return a.exec();
}
Beside the use of a button class that will allow you to display rich text, you also need to make sure your connections are correct.
In your example, you're connecting the clicked signal of the button to the clear() slot of the label, which is non-sense.
To exit your app when the button is clicked, you need to close the main window. Here is the code to get the right connection :
QObject::connect(button, SIGNAL(clicked()),Main, SLOT(close()));
Changing this single line of code in your example is not enough, because your label is drawn on top of your button, so it's not possible to graphically click on it. You need to hide your label and put some text into your button :
button->setText("Hello");
label->setVisible(false);
Regarding the rich text feature in a QPushButton, AFAIK it is not possible to do it with a QPushButton.
UPDATE :
Here is a way to put some richtext on a QPushButton. It uses the solution described by my comment : painting a QTextDocument onto a pixmap and setting this pixmap as the button's icon.
#include <QtGui/QApplication>
#include <QLabel>
#include <QPushButton>
#include <QtGui>
#include <QTextDocument>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow *Main=new QMainWindow;
QPushButton *button = new QPushButton(Main);
QTextDocument Text;
Text.setHtml("<h2><i>Hello</i> ""<font color=red>Qt!</font></h2>");
QPixmap pixmap(Text.size().width(), Text.size().height());
pixmap.fill( Qt::transparent );
QPainter painter( &pixmap );
Text.drawContents(&painter, pixmap.rect());
QIcon ButtonIcon(pixmap);
button->setIcon(ButtonIcon);
button->setIconSize(pixmap.rect().size());
QObject::connect(button, SIGNAL(clicked()),Main, SLOT(close()));
Main->show();
return a.exec();
}
Take a look here. Widget called QwwRichTextButton.
The QwwRichTextButton widget provides a button that can display rich text.