Qt - Set display text of non-editable QComboBox - c++

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.

Related

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;
};

QAbstractItemView Tab Focus While Editing Item

I have a QTreeView populated with items from a model. When a call to edit() is made on an index, a custom editor displays. The editor consists of two QLineEdit widgets.
I want the focus to switch between the two QLineEdit widgets when Tab is pressed. However, pressing Tab cycles through everything else on my program. All my QPushButton and QTabWidget objects are included in the Tab order even though they are completely different widgets than my editor.
I've tried setting the tab order using setTabOrder() to loop it between the two QLineEdit widgets, however this still doesn't isolate the editor widget from the surrounding widgets. Why is this happening?
NOTE: I'm not trying to disable tab ordering anywhere else, just isolate it to my editor for the time being.
Thanks for your time!
This can be easily implemented using QWidget::focusNextPrevChild as follows:
class EditWidget : public QWidget
{
public:
EditWidget(QWidget *pParent) : QWidget(pParent)
{
QHBoxLayout *pLayout = new QHBoxLayout(this);
setLayout(pLayout);
pLayout->addWidget(m_pEdit1 = new QLineEdit ());
pLayout->addWidget(m_pEdit2 = new QLineEdit ());
}
bool focusNextPrevChild(bool next)
{
if (m_pEdit2->hasFocus())
m_pEdit1->setFocus();
else
m_pEdit2->setFocus();
return true; // prevent further actions (i.e. consume the (tab) event)
}
protected:
QLineEdit *m_pEdit1;
QLineEdit *m_pEdit2;
};

Close button only on active tab of QTabWidget

To save space in a QTabWidget, I would like to show the close icon only for the current tab, like e.g. Firefox is doing:
Is there a simple way using a style sheet, some thing like (not working like this)
QTabBar::tab::!selected::close-button {visible: false;}
or do I have to subclass QTabWidget to get the desired behavior?
You won't need to subclass anything, you can use QTabWidget::tabBar() method to obtain a reference (i.e. QTabBar *) to the tab bar associated with your QTabWidget. (Note that this method is no longer protected, so it can be accessed without subclassing the class)
QTabBar *tabBar = tabWidget->tabBar();
You can now use tabBar reference to hide close buttons on non-current tabs. For example to hide ith button, you can do:
tabBar->tabButton(i, QTabBar::RightSide)->hide();
So a simple workflow could be as follows:
Connect QTabWidget::currentChanged(int index) signal to a slot.
In that slot hide all close buttons other than the button at index.
You can subclass QTabWidget to get access to the QTabBar widget using protected method QTabWidget::tabBar. Then you can connect to the QTabBar::currentChanged signal and hide close button for not selected tabs manually:
QTabBar::ButtonPosition closeSide =
(QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
for (int i = 0; i < toolbar->count(); ++i)
{
if (i != toolbar->currentIndex())
{
QWidget *w = toolbar->tabButton(i, closeSide);
w->hide();
}
}
hide() leaves empty space for the invisible close button. This looks funny.
Set the width to 0 instead.

QDialog on accept return custom class object

I'm using qt-creator to build a little QT application.
I have a main window where I have some controls like a "new contact" button.
Pressing the button a QDialog is shown, it contains 3 line edits: name, mobile and email.
The dialog is shown through the Signal/Slot system. It works fine but I want to create a Contact object when OK is clicked and I want to give back that Contact to my main window in order to put it in a QList created in the main window code.
The approach is:
QMainWindow -> new contact -> QDialog is shown
QDialog -> ok -> QMainWindow
Should I pass the QList from the main window to the QDialog as argument or there is a best way?
Should I pass the QList from the main window to the QDialog as argument or there is a best way?
In my opinion, best would be a custom QDialog subclass with three QLabels and 3 QLineEdits.
The labels would get the following type of values:
Label 1: name
Label 2: mobileNumber
Label 3: email
You would use then QLabels and QLineEdits to display them with the input coming from the user.
Then, as your program probably already does, just handle the "accept" event respectively. You could use the following method to retrieve the text entered by the end user:
text : QString
This property holds the line edit's text.
Setting this property clears the selection, clears the undo/redo history, moves the cursor to the end of the line and resets the modified property to false. The text is not validated when inserted with setText().
The text is truncated to maxLength() length.
By default, this property contains an empty string.
Then, in the handler of the accepted signal, you could call three accessor methods, like:
QString name() const { return nameLineEdit->text(); }
QString mobileNumber() const { return mobileNumberLineEdit->text(); }
QString email() const { return emailLineEdit->text(); }
You could also store that in a dedicated structure depending on you build up your data representation, so the structure would be something like this:
struct Contact {
QString name;
QString mobileNumber;
QString email;
};
and then you would have the accessor for that as follows
Contact contact() const;
Make a subclass of QDialog. Call Yourclass::exec() to show the dialog (exec is a function in QDialog), then afterwards Yourclass::contactDetails() to get them. contactDetails is a perfectly ordinary member function that you have to write.

How to read a text from a text field from c++

I have a text field and a button purely designed in c++(without importing a qml doc). How do i read the text from the text field when I click the buton.
I am unable to find a function associated for that.
To hook up the button to a method, use the following code:
button = new Button();
texField = new TextField();
connect(button, SIGNAL(clicked()), this, SLOT(onClicked());
Then define the onClicked slot as so:
void ClassName::onClicked() {
qDebug() << textField->text(); //print the textField's text
}
For this to work, this method has to be marked in the class as a Q_SLOT and the object itself must be marked as a Q_OBJECT.