QT Making a Dropdown Menu Widget Programmatically - c++

I am using QT 5.5 with Mac OSX. I want to make several dropdown menu widgets programmatically that will have various options that can change the values of certain variables.
So for example, I would have dropdown menu 1 represent variable "command" have:
- Q
- W
- E
- R
And by selecting whichever one, then it would make command = Q, or command = W. So that way, I can send command to another program knowing that I sent Q, or W.
My current mainwindow looks something like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//******* Set up
ui->setupUi(this);
ui->centralWidget->setLayout(new QVBoxLayout);
// 01: Creation of Console
console = new Console;
console->setEnabled(false);
/************** Adding Widgets *********************/
//creation and attribution of slider
slider = new QSlider();
slider->resize(255, 20);
slider->setOrientation(Qt::Horizontal);
slider->setRange(0, 255); //0-255 is range we can read
//creation and attribution of the lcd
lcd = new QLCDNumber();
lcd->setSegmentStyle(QLCDNumber::Flat);
lcd->resize(255, 50);
//03: Adding widgets to layout
//add console as a widget to the main widget
//layout with slider and lcd underneath console
ui->centralWidget->layout()->addWidget(console);
ui->centralWidget->layout()->addWidget(slider);
ui->centralWidget->layout()->addWidget(lcd);
////////I WANT TO ADD VARIOUS DROPDOWN MENUS HERE NEXT TO EACH OTHER////////
/************** Connection Events ***********************/
....
}

Assuming you want a ComboBox, Here is how you can do it:
QStringList commands = { "Q", "W", "E", "R" };
QComboBox* combo = new QComboBox(this);
combo->addItems(commands);
connect( combo, &QComboBox::currentTextChanged, this, &MainWindow::commandChanged);
Now you will get the command text when user changes the combo box item. and you can write your code based on that.
MainWindow::commandChanged(const QString& command_text)
{
//Do the logic based on command_text
}
Another option if you want to choose combobox item texts differently is that you set itemData for combobox items. and get them in your slot by currentData property of the ComboBox.

Related

How to get the text of a Qcomplete in a Qcombobox

I have a combobox that I fill with a QList and now I have generated a search engine with the help of the QCompleter, so far everything is fine, but I have edited it to make it visually more attractive, and it worked correctly until I have trouble selecting with the mouse one of the options that the QCompleter threw at me and the selection does not respect me, it only respects me if I give an Enter with the keyboard, but only for a moment.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qApp->setStyleSheet("QAbstractItemView#completerPopup {font: 15pt ;color: rgb(255, 255, 255);}");
}
QCompleter *completer = new QCompleter(list, this);
completer->setFilterMode(Qt::MatchContains);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->popup()->setObjectName("completerPopup");
ui->cobobox->setCompleter(completer);
I manage to make it work but I have to remove some lines of code that are the ones that help me edit the QCompleter as Pupop.
QCompleter *completer = new QCompleter(list, this);
completer->setFilterMode(Qt::MatchContains);
completer->setCaseSensitivity(Qt::CaseInsensitive);
ui->cobobox->setCompleter(completer);
The error it throws when I select is the following
Setting a QCompleter on non-editable QComboBox is not allowed.
In the qtcreator form designer select your combobox and in properties window mark editable checkbox.

QObject::findChild returns 0 for QLabels added to statusbar

I created a application running in a QMainWindow using qtcreator, so the typical way.
I added two 'manually' (meaning: not with the Form editor) created qlabels to the statusbar:
in the header:
QLabel *label_timestamp;
QLabel *contentLabel_timestamp;
in the constructor:
MainWin::MainWin(const CmdLineOptions &opts, QWidget *parent)
: QMainWindow(parent),
ui(new Ui::MainWin),
m_connectionStatusLabel(new QLabel),
m_client(new QMqttClient),
m_mqttmanager(new MQTTManager(m_client)),
m_mqttServerName("localhost")
{
ui->setupUi(this);
label_timestamp = new QLabel(this);
contentLabel_timestamp = new QLabel(this);
label_timestamp->setText("system time");
contentLabel_timestamp->setText("dd.mm.yyyy, hh:mm:ss:zzz"); /* just testing output */
statusBar()->addPermanentWidget(label_timestamp);
statusBar()->addPermanentWidget(contentLabel_timestamp);
}
If I do a
Label *label = findChild<QLabel *>(QString("contentLabel_")+objName);
elsewhere in this class implementation with objName being 'timestamp', of course, findChild() returns 0. It's working fine with other QLabels created using QtCreator in the form editor, findChild() finds them all. Isn't the statusbar widget and its content also a child of ui? Does somebody eventually know a way out of there?
I want to use findChild to generically fill my labels following a naming scheme with content I receive over MQTT, this is the background. Would be great if the statusbar content would need a special handling but could also be handled in this dynamic approach.
Thanks a lot
findChild uses the objectName, in the case of Qt Creator this establishes it in the MOC, but in your case you must establish it:
label_timestamp = new QLabel(this);
contentLabel_timestamp->setObjectName("label_timestamp");
contentLabel_timestamp = new QLabel(this);
contentLabel_timestamp->setObjectName("contentLabel_timestamp");
And then you can recover it with:
QLabel *label_1 = findChild<QLabel *>("label_timestamp");
if(label_1){
// some code
}
QLabel *label_2 = findChild<QLabel *>("contentLabel_timestamp");
if(label_2){
// some code
}

Which UI item allows dynamic expansion on the go in Qt?

Suppose I have a single text box and a radio button placed below the text box .
What I want is that if the user enters some text and ALSO clicks the radio button a similar text box and a radio button should appear just below. And similar thing should happen if the user does that for new UI items.
Any suggestions what classes I should be looking for?
The relevant class you need to handle the inserting of new widgets is one of the QLayout subclasses, most likely QVBoxLayout it sounds like. This will allow you to insert a new textbox and radio button at the bottom of the layout, which will then automatically expand to fit these new widgets.
Inserting the new objects is pretty straightforward. Connect a slot to a signal of the QRadioButton that's at the bottom of the layout, like the QRadioButton::toggled or QRadioButton::clicked signals. This slot will check if the above textbox has any text in it, and, if so, insert a new textbox/radio button pair below them.
To be clear, this slot should be a method of the widget that uses the layout to arrange its sub-widgets. For example, if you're putting all these objects in a QGroupBox, then that's the object to which you'd add the slot I'm describing.
Here is an (untested) example:
class Group : public QGroupBox {
Q_OBJECT
public:
Group(QWidget* parent = nullptr) : QGroupBox(parent)
{
layout = new QVBoxLayout(this);
insertNewRow();
}
private slots:
void insertNewRow(bool checked = true) {
/* You might want to make this remove the row if the button is unchecked */
if (!checked)
return;
/* Only add row if text box is non-empty */
if (textBoxes.isEmpty() || textBoxes.last()->text().isEmpty())
return;
/* Disconnect slot for previous radio button */
QObject::disconnect(radioButtons.last(), 0, 0, 0);
/* Add new text box and button, labeled Button 1, Button 2, etc. */
textBoxes.append(new QLineEdit("", this));
radioButtons.append(new QRadioButton(QString("Button %1").arg(textBoxes.size())), this));
/* Connect signal/slot to add new row when clicked */
QObject::connect(radioButtons.last(), &QRadioButton::toggled, this, &Group::insertNewRow);
}
private:
QVBoxLayout* layout;
QList<QLineEdit*> textBoxes;
QList<QRadioButton*> radioButtons;
};

Qt - Set display text of non-editable QComboBox

I would like to set the text of a QComboBox to some custom text (that is not in the QComboBox's list), without adding this text as an item of the QComboBox.
This behaviour is achievable on an editable QComboBox with QComboBox::setEditText(const QString & text).
On a non-editable QComboBox, however, this function does nothing.
Is it possible to programmatically set the display/edit text of a non-editable QComboBox to something that is not in its list?
Or do I have to find another way (e.g. use a QPushButton with a popup menu)
EDIT: Consider an editable QComboBox with InsertPolicy QComboBox::NoInsert. If the user types in something and hits enter, the entered value will be used but not added to the list. What I want is this behaviour to change the 'current' text programmatically, but without allowing the user to type in some text himself. The user can choose something from the QComboBox, but some time later, I may want to override the 'current' text.
I had the same problem when I subclassed QComboBox to make a combo box of check boxes. I wrote a small function to programmatically change the text displayed in the combo box, but I didn't want to enable the user to edit that text. The solution was to set the combo box as editable:
this->setEditable(true);
and the QComboBox::lineEdit() to read only. Refer to the function:
void CheckedComboBox::setText(QString text)
{
QLineEdit *displayedText = this->lineEdit();
displayedText->setText(text);
displayedText->setReadOnly(true);
}
Reimplement paintEvent : https://github.com/qt/qtbase/blob/28d1d19a526148845107b631612520a3524b402b/src/widgets/widgets/qcombobox.cpp#L2995
and add this line : opt.currentText = QString(tr("My Custom Text"));
Example :
QCustomCheckComboBoxFilter.h
...
protected:
void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE;
...
QCustomCheckComboBoxFilter.cpp
...
void QCustomCheckComboBoxFilter::paintEvent(QPaintEvent *)
{
QStylePainter painter(this);
painter.setPen(palette().color(QPalette::Text));
// draw the combobox frame, focusrect and selected etc.
QStyleOptionComboBox opt;
initStyleOption(&opt);
opt.currentText = QString(tr("My Custom Text"));
painter.drawComplexControl(QStyle::CC_ComboBox, opt);
// draw the icon and text
painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
}
...
I supposed that you want to have a combo box with "A", "B", "C" as actual data and "This is A"
, "This is B" and "This is c" as what is displayed in QComboBox. Here is the code:
box.addItems(QStringList () << "This is A"<< "This is B"<< "This is C");
box.setItemData(0, "A");
box.setItemData(1, "B");
box.setItemData(2, "C");
You can get the actual data with this code :
QString actual = box.itemData(0).toString();//actual will be = "A";
qDebug()<<actual;//"A"
Note: You can almost set every data types that you want for a combo box Item. Even more, you can set more that just one additional data for each item with the third parameter of setItemData.
I ended up using a QPushButton with a popup menu.
I added the items I had in the list of my QComboBox as QActions to the menu.
A menu can be set on a QPushButton with
QPushButton::setMenu(QMenu* menu)
.
The text on the button can easily be set with
QPushButton::setText(const QString &)
and is unrelated to the text in the popup menu, which is what I wanted.

Disabling a QCheckbox in a tricky way

I want to make a QCheckBox named "Show Captions" disable another QCheckBox named "Show captions if no title" when the first is checked, but my problem is that how I can make it disabled immediately when the user checks the first checkbox.
SetupSlideShow::SetupSlideShow(QWidget* parent)
: QScrollArea(parent), d(new SetupSlideShowPriv)
{
QWidget* panel = new QWidget(viewport());
setWidget(panel);
setWidgetResizable(true);
QVBoxLayout* layout = new QVBoxLayout(panel);
d->showComment = new QCheckBox(i18n("Show captions"), panel);
d->showComment->setWhatsThis( i18n("Show the image caption at the bottom of the screen."));
d->showTitle = new QGroupBox(i18n("Show title"), panel);
d->showTitle->setWhatsThis( i18n("Show the image title at the bottom of the screen."));
d->showTitle->setCheckable(true);
d->showCapIfNoTitle = new QCheckBox(i18n("Show captions if no title"), panel);
d->showCapIfNoTitle->setWhatsThis( i18n("Show the image caption at the bottom of the screen if no titles existed."));
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(d->showCapIfNoTitle);
d->showTitle->setLayout(vbox);
layout->addWidget(d->showLabels);
layout->addWidget(d->showComment);
layout->addWidget(d->showTitle);
}
Doesn't this work?
connect(d->showComment, SIGNAL(toggled(bool)), d->showCapIfNoTitle, SLOT(setDisabled(bool)));
The call to paintEvent() isn't really doing anything for you regarding immediacy. Nothing will be repainted until control returns to the event loop (after your constructor exits). It is more typical to call update() but even this is unnecessary when changing the properties of built in widgets.
To link the check boxes, define a slot for the stateChanged() signal of showComment, connect the signal to your slot in your constructor above (by calling connect(), and in that slot, call d->showCapIfNoTitle->setCheckState(d->showComment->checkState()).