How to create a Qt dialog with dynamic number of text inputs? - qt

Is there a way to make a form/dialog with a dynamic number of text input elements (e.g. Line Edit widget)? So the user can choose to "add another" item.

If you have a dialog with a layout. You could connect a slot to a button in the dialog that will add an item by retrieving the dialog layout and adding a new item.
so something like:
void MyDialog::on_addButton_clicked()
{
QLayout *layout = layout();
if (layout) {
layout->addWidget(new QLineEdit());
}
}
And if you give the items an unique name with: setObjectName("someName") you could later use findChild<QLineEdit*>("someName"); to find all added line edits for further processing.

Related

I created a QToolButton and the label would include "..." but it looks like Qt removes them, is that right?

I use the following code, the first part, creating the QToolButton, is from Designer/moc, the rest I added.
// Moc part
QToolButton * f_tool_button = new QToolButton(bottom_grid);
f_tool_button->setObjectName(QStringLiteral("f_tool_button"));
f_tool_button->setText(QApplication::translate("MainWindow",
"Tool Button...", 0));
// What I added
f_action = new QAction(this);
f_action->setObjectName(QStringLiteral("f_action"));
f_action->setText(QApplication::translate("MainWindow",
"&Click...", 0));
f_menu.reset(new QMenu("Tool Button Menu ...", this));
f_menu->addAction(f_action);
f_tool_button->setDefaultAction(f_menu->menuAction());
If I don't call setDefaultAction(), the title appears as expected.
When I add the default action, the label seems to be replaced by the f_menu title, "Tool Button Menu ..." (I put a somewhat different label on purpose). But somehow the "..." gets removed from the name.
Any idea about this problem? Is that a special Qt feature?
The QToolButton displays text from QAction's iconText property (not text). text is meant to be used in menu entries, whereas iconText is meant to be displayed in tool bars. When not set, iconText is a stripped version of text.
To override the default behavior of stipping text to generate iconText, you can set the desired iconText for your QAction using QAction::setIconText() (i.e. f_action->setIconText("Click..."); right after your f_action->setText call).

Adding tab to QTabWidget. is empty?

Well, the thing is I have a tabwidget created in qtcreator, with many tabs and in the tabs there are many lineedit and other objects.
The closeable property of the tabWidget is set to true.
I execute the program and close the tabs, but when I want to reopen the tab, it's empty, I'm using this code:
tabs->addTab(new QWidget(),"TAB 1");
I want to use the same tab create on the design of qtcreator.
Your problem is that you are adding empty widget in your code:
tabs->addTab(new QWidget(),"TAB 1");
Instead you need to keep you widgets and add them like that:
QWidget* widget; // it is stored
int index = ui->tabWidget->addTab(widget, "TAB 1");
Where to take these widgets?
It is not enough to set closable to true, you also to use signal/slot:
connect(ui->tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
And finally:
void YourWindow::closeTab(int index)
{
// do something else
QWidget* widget = ui->tabWidget->widget(index);
ui->tabWidget->removeTab(index);
// here you can remember it and use later when adding tab
}

QTreeWidget right click menu

I looked around and it seems that the problem is present not only for tree widget but also for other widgets. But in my case, I found a solution, although an incomplete one. I am adding actions to my tree widget, so that when you right click on it, a popup with these actions appears. However, when I add items to my tree widget and I right click on them, the same popup appears.
What I would like to do is that when you right click on the tree widget, a tree widget popup menu appears and when you right click on items, another corresponding popup menu appears. Does anybody knows how to do this?
First,config QTreeWidget to response(emit signal) right mouse click:
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
Second,connect the signal with your slot "MainWindow::prepareMenu":
connect(treeWidget,&QTreeWidget::customContextMenuRequested,this,&MainWindow::prepareMenu);
Third,create context menu in the slot:
void MainWindow::prepareMenu( const QPoint & pos )
{
QTreeWidget *tree = treeWid;
QTreeWidgetItem *nd = tree->itemAt( pos );
qDebug()<<pos<<nd->text(0);
QAction *newAct = new QAction(QIcon(":/Resource/warning32.ico"), tr("&New"), this);
newAct->setStatusTip(tr("new sth"));
connect(newAct, SIGNAL(triggered()), this, SLOT(newDev()));
QMenu menu(this);
menu.addAction(newAct);
QPoint pt(pos);
menu.exec( tree->mapToGlobal(pos) );
}
First you should set the context menu policy to CustomContextMenu:
treeView->setContextMenuPolicy(Qt::CustomContextMenu);
Then you can connect to the QWidget::customContextMenuRequested(const QPoint&) signal and show your context menu.
For those who prefer to use designer more, here is another way to do it:
1) Set context menu policy to custom context menu
Either by code:
ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
or using graphical designer, click on the tree widget and set it using Property Editor:
2) Create Handler function
In designer, right click on the treeWidget and select "Go to Slot..." option. A window similar to this will appear:
Click on the "CustomContextMenuRequested(QPoint)" option. Handler function will be defined, declared, and it will be connected automatically.
void MainWindow::on_treeWidget_customContextMenuRequested(const QPoint &pos)
{
// this function will be called on right click
}
This step can also be done by defining and connecting the slot function yourself.
3) Create the options on the context menu.
Go to action editor tab (Usually docked at the bottom of designer). Add actions you want to have on context menu by clicking new button on top left. You will encounter such an interface :
You can (optionally) have a tooltip or icon for the action, or make it checkable. You can crate a shortcut like Ctrl+C for a copy action.
4) Create the menu and fire it
void MainWindow::on_treeWidget_customContextMenuRequested(const QPoint &pos)
{
QMenu menu(this); // add menu items
menu.addAction(ui->actionDelete);
menu.addEdit(ui->actionDelete);
...
ui->actionDelete->setData(QVariant(pos)); // if you will need the position data save it to the action
menu.exec( ui->treeWidget->mapToGlobal(pos) );
}
5) Create handler functions for each action
Like in step 2, either create slot function and connect it manually, or right-click on on an action, click the "Go to slots..." option and select triggered() slot.
6) Lastly, apply your logic in the slot function
void MainWindow::on_actionEdit_triggered()
{
QTreeWidgetItem *clickedItem = ui->treeWidget->itemAt(ui->actionDelete->data().toPoint());
// your logic
}
Take a look at overloading QAbstractItemModel and providing your own OnContextMenuRequested. Via this function you can have different items create different context menus.
Here's some shortened pseudo-ish code from one of my projects that may be helpful:
void MyModel::OnContextMenuRequested(const QModelIndex& index, const QPoint& globalPos)
{
// find 'node' corresponding to 'index'
vector<pair<string,BaseNode*> > actions = node->GetActions(true);
if(actions.size()==0) return;
// the ptr list helps us delete the actions
boost::ptr_list<QObject> actionPtrList;
QList<QAction*> qtActions;
for(unsigned int i=0;i<actions.size();i++)
{
QAction* act = new QAction(actions[i].first.c_str(),NULL);
act->setData(qVariantFromValue(actions[i].second));
actionPtrList.push_back(act);
qtActions.append(act);
}
// create and show the context menu
QMenu *menu = new QMenu("Item actions",NULL);
actionPtrList.push_back(menu);
QAction* act = menu->exec(qtActions,globalPos);
if(act==NULL) return;
// act on the resulting action 'act'
}

Connect custom widget to QWidgetTab for sizing

I'm trying to get every widget to scale with change in window size. I have a main window which has a QTabWidget with a QWidget holder for each tab. I then have a custom widget with a seperate .ui file that I set to fill the QWidget space of the tab. The problem is, I can't get the contents of the QWidget to expand, only the tab and QWidget of the main window. Also, I noticed if i change the ui->setupUi( ) argument for the custom widget from "this" to "parent" the problem is fixed, and the custom widget will scale correctly. The only problem with this is none of the buttons work when I do that. The application output reads out "No Slot" found errors for the buttons. What is the correct way to make this connection?
Edit: Example code
MainWindow:: ...
{
//assign customWidget to widget placeholder on tabWidget.
//holder is just a blank widget set in gridLayout on tab widget.
CustomWidget * customWidget = new CustomWidget(ui->customWidgetHolder);
setCentralWidget(ui->tabWidget);
//This gets the sizing I want with the tabs, but
//doesn't pass it past the customWidgetHolder.
}
From what I undertand, you need to use a layout, for your custom widget inside your tab
QTabWidget* tabWidget = new QTabWidget();
QWidget* tab = new QWidget();
QVBoxLayout* verticalLayout = new QVBoxLayout(tab);
YourWidget* widget = new YourWidget(tab);
verticalLayout->addWidget(widget);
tabWidget->addTab(tab, QString());
But you'll need to be more specific (code sample ?) about the SIGNAL/SLOT connection you've made if you want answer about it.

On Qt widgets like DoubleSpinBox or ComboBox, how do i have custom right click menu

I have a few combo-boxes and double spin boxes on my Qt Dialog. Now I need a "ResetToDefault" item on a menu that comes up when you right click on the widget (spin box or combo box).
How do i get it. Is there some way I can have a custom menu that comes up on right click or Is there a way i can add items to the menu that comes on right click.
First, for Qt4, the simplest way is to create an action to reset the data, and add it the the widget using the addAction method (or use the designer). Then, set the contextMenuPolicy attribute to Qt::ActionsContextMenu. The context menu will appear and the action will be triggered.
Code example:
QAction *reset_act = new QAction("Reset to default");
mywidget->addAction(reset_act);
mywidget->setContextMenuPolicy(Qt::ActionsContextMenu);
// here connect the 'triggered' signal to some slot
For Qt3, you might have to intercept the context menu event, and thus inherit the QSpinBox and others. Or maybe you can intercept the context menu event from the main window, detect if it occurred above the widget supposed to have a context menu (using the QWidget::childAt method) and show it there. But you'll have to test.
For Qt4, you can do this for an editable QComboBox by using your own QLineEdit. Create a derived QLineEdit class which implements the contextMenuEvent
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
MyLineEdit(QWidget* parent = 0) : QLineEdit(parent){}
void contextMenuEvent(QContextMenuEvent *event)
{
QPointer<QMenu> menu = createStandardContextMenu();
//add your actions here
menu->exec(event->globalPos());
delete menu;
}
};
Then, use the setLineEdit function of QComboBox to set the line edit
MyLineEdit* edit = new MyLineEdit();
comboBox->setLineEdit(edit);
The combo box will now use your line edit class. The createStandardContextMenu function creates the normal context menu and you can add any new actions to it that you like in the contextMenuEvent handler before it is shown.
If the QComboBox is not editable then it doesn't have a default context menu so using the Qt::ActionsContextMenu method is much simpler.
QAbstractSpinBox also has a setLineEdit function so you can use a similar technique. Although, for some reason the setLineEdit function is protected on QAbstractSpinBox but public on QLineEdit.

Resources