Adding menu on QPushButton using QComboBox - c++

I am trying to implement a popup menu on QPushButton using QComboBox popup function.
When I click on the button a menu appears but their is some space between the button and the menu. How do I remove that?
I also want the text color to remain fixed when I hover on an item in the menu.
How do i do that?
I am trying to solve this already for 3 days but not getting any solution by CSS nor any QComboBox function.
Thank you.

You can use a QToolButton instead of QPushButton and add actions to the QToolButton. You should create your custom QWidgetAction to add to the popup menu.
This is sample QWidgetAction:
#include <QWidgetAction>
class myCustomWidgetAction: public QWidgetAction
{
Q_OBJECT
public:
explicit myCustomWidgetAction(QWidget * parent);
protected:
QWidget * createWidget(QWidget *parent);
};
myCustomWidgetAction::myCustomWidgetAction(QWidget * parent):QWidgetAction(parent) {
}
QWidget * myCustomWidgetAction::createWidget(QWidget *parent){
myCustomWidget * widget=new myCustomWidget(parent);
return widget;
}
You can then add your widget to the toolButton to be diaplayed in a popup menu:
myCustomWidgetAction * widgetAction = new myCustomWidgetAction(this);
ui->toolButton->addAction(widgetAction);
Your custom widget can be a list containing different elements or it can be any other widget. You can also add multiple instances of myCustomWidgetAction to the toolButton.

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

How to know parent menu of a given QAction?

I have a list of QActions, some are added to the top level menu and few are added to submenus of top level.
Is there any way to know parent menu name of each actions?
QAction *act;
I'm trying act->parentWidget(). But how can I get menu name from this?
You can check if the result of act->parentWidget() if it is a valid pointer, if so you can manipulate as a normal widget.
To get the menu name, it depends on which widget you are using.
If is QMenu, you can retrieve the menu title via the title function.
QAction *act;
...
QWidget *widget = act->parentWidget();
if (widget) {
QMenu *menu = dynamic_cast<QMenu*>(widget);
menu->title();
}

How to change contents of QMainWindow dynamically

I have a QMainWindow that starts out with nothing but a menubar with a menu that has two options. When the first is clicked the window should be populated with QLabels and various input widgets to recieve data. When the second option is clicked the window should be populated with a QTextEdit(obviously removing whatever was on the window at the time)
The following is code I have tried :
void OrderWindow::displayAddOrder(){
QVBoxLayout* tlayout = new QVBoxLayout();
QHBoxLayout* row = new QHBoxLayout();
row->addWidget(nameLbl);
tlayout->addLayout(row);
qDeleteAll(children());
delete layout();
setLayout(tlayout);
}
It's a bit messy since I've been trying various things. When I click on a menu option with this code it simply says the application has stopped working.
Any help would be appreciated.
You have at least the following options:
Always show the actual widget, and hide the rest. This is simple in case of two widgets like in your example. You could use this technique with the observer design pattern for any number of widgets.
Use the QStackedWidget class which basically behaves the way as your custom observer pattern implementation would be, although you will need to use an extra class for this.
Therefore, I would suggest to write the following code:
orderwindow.h
...
class QStackedWidget;
class OrderWindow
{
...
public:
explicit OrderedWindow(QWidget *parent);
...
private:
QStackedWidget m_stackedWidget;
...
}
...
orderwindow.cpp
#include "orderwindow.h"
#include <QStackedWidget>
...
OrderWindow::OrderWindow(QWidget *parent)
: QWidget(parent)
, m_stackedWidget(new QStackedWidget(this))
{
QWidget *firstPageWidget = new QWidget;
QWidget *secondPageWidget = new QWidget;
m_stackedWidget->addWidget(firstPageWidget);
m_stackedWidget->addWidget(secondPageWidget);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(stackedWidget);
setLayout(layout);
}
...
void OrderWindow::displayAddOrder() {
m_stackedWidget->setCurrentWidget(nameLbl);
}
...
you can use a QStackedWidget
start with showing an empty page and then show the correct page as needed:
there is then no need to mess with adding or removing widgets
Yes, you can use a QStakedWidget if your input options are fixed. If it's not, I suggest you to use an abstract factory pattern to create the stacked widget content. This woluld make your code more readable.

Why cant a QToolButton be hidden after it is added to a QToolBar?

This works...
QToolButton * toolbutton = new QToolButton(this);
//hide before addWidget
toolbutton->hide();
addWidget(toolbutton);
But this doesn't
QToolButton * toolbutton = new QToolButton(this)
addWidget(toolbutton);
//hide after addWidget
toolbutton->hide();
Is there an alternative so I can actually hide after a QToolButton after it is added to a QToolBar? I need to during runtime.
QAction * QToolBar::addWidget ( QWidget * widget )
You should hide returned QAction
One alternative is to add a QAction instead of a widget and then hide the QAction. I've tried it and it works with QAction::setVisible(false).
You can also do something like QToolBar::actions().at(3)->setVisible(false); if you know the position of the widget in the QToolBar.
toolbar->actions().at(0)->setVisible(false);