How to change QStackedWidget index from Qdialog - c++

My application have an "actionhelp" in the menu bar which when clicked opens up a QDialog that contains an ok button at the other side in the mainwindow i have a QStackedWidget
So my question is how to change the index of the stackedwidget when i press that ok button in the QDialog??

Signals and slots. Connect the signal from the ok button (or emit one of your own when checking QDialog::Accepted after it closes) to a slot that will change the index in the QStackedWidget.
Example code:
Create and connect QAction in main method:
QAction *displayDialog = new QAction("Display Dialog", this);
connect(popup, SIGNAL(triggered()), this, SLOT(showDialog()));
Display Dialog:
void showDialog()
{
YourDialog *dialog = new YourDialog(this);
int return_code = dialog.exec();
if (return_code == QDialog::Accepted)
{
int index = someValue;
qStackedWidget.setCurrentIndex(index);
}
}

Assuming you have a line edit on your dialog and you want to change the index of stacked widget based on the line edit value ( or a spin box ):
//your dialog
//the constructor
YourDialog::YourDialog(QWidget*parent)
:QDialog(parent)
{
connect(ur_ok_btn, SIGNAL(clicked()), SLOT(accept ()));
}
//access to line edit value
QString YourDialog::getUserEnteredValue(){return ur_line_edit->text();}
Where you create an instance of YourDialog class :
//your main window
YourDialog dlg;
if( dlg.exec() == QDialog::Accepted ){
int i = dlg.getUserEnteredValue().toInt();
ur_stacked_widget->setCurrentIndex(i);
}

Related

QListWidget with custom widgets - not triggering itemClicked signal

I have listwidgetitem's that have a custom widget (step_widget) which contains 3 QPushButtons and a QLabel.
When I press one of the buttons in the widget, it is not triggering itemClicked which i need to see the index of the listwidget that was clicked. If i click the QLabel, the signal is triggered and i am able to obtain the index. How can trigger the signal when one of the buttons is pressed? Why does it not trigger?
QListWidgetItem *item = new QListWidgetItem();
stepWidget *step_widget = new stepWidget();
ui->listWidget->addItem(item);
ui->listWidget->setItemWidget(item,step_widget);
The itemClicked() signal is not emmited because the QPushButton consumes the click event.
There is the simplest solution I've found.
First, in your class stepWidget add a signal that will be emitted when any QPushButton is clicked, for example:
signals:
void widgetClicked();
Then connect the clicked() signal of every QPushButton with that signal. This code is in the constructor of the widget stepWidget:
connect(ui->pushButton1, &QPushButton::clicked, this, &stepWidget::widgetClicked);
connect(ui->pushButton2, &QPushButton::clicked, this, &stepWidget::widgetClicked);
connect(ui->pushButton3, &QPushButton::clicked, this, &stepWidget::widgetClicked);
To test it I added 10 widgets to a QListWidget that reside in the MainWindow class. You must connect that signal to a slot (in this case I use a C++11 Lambda Function, but you can create a slot instead, it's fine) where you establish the current item as the item under the widget. This code is located in the constructor of MainWindow:
for (int i = 0; i < 10; ++i) {
QListWidgetItem *item = new QListWidgetItem;
stepWidget *step_Widget = new stepWidget;
ui->listWidget->addItem(item);
ui->listWidget->setItemWidget(item, step_Widget);
connect(step_Widget, &stepWidget::widgetClicked, [=]() {
ui->listWidget->setCurrentItem(item);
});
}
Now, this will not make the itemClicked() signal to be emitted because the user not clicked the item. But I advice you to connect instead the signal currentRowChanged() as it will be emitted with this code and also it has the advantage that it allows you to directly obtain the row. Once you have the row you can obtain the item and the widget, evidently.
However, this procedure has the inconvenient that the currentRowChanged() signal will be emitted even when the user selects a row with the keyboard or when the user press and slide the mouse over the QListWidget without releasing it.
On workaround could be, for example, using a flag as an attribute for your MainWindow class that is always false except during this connection:
connect(ste_pWidget, &stepWidget ::widgetClicked, [=]() {
buttonPressed = true;
ui->listWidget->setCurrentItem(item);
buttonPressed = false;
});
Then you must manipulate two signals from the QListWidget: clicked() and currentRowChanged(). I choose clicked() instead of itemClicked() because it gives almost directly access to the row:
void MainWindow::on_listWidget_clicked(const QModelIndex &index)
{
ui->statusBar->showMessage(tr("Row clicked: %1").arg(index.row()), 1000);
}
void MainWindow::on_listWidget_currentRowChanged(int currentRow)
{
if (buttonPressed) {
ui->statusBar->showMessage(tr("Row clicked: %1").arg(currentRow), 1000);
}
}
what you can simply do is, make your qpushbutton to qlabel and then qpushbutton will become clickable.
You can then override this method :- on_listWidget_itemClicked(QListWidgetItem *item) for double click on qpushbutton.
I tried it & it worked perfectly, its quite simple workaround.

How to lock all toolbars via menu in Qt?

I am experimenting with Qt Creator and the Application Example.
I would like to add a checkable menu entry to a toolbar menu that reads "Lock toolbars" and, when checked, locks the positions of all tool bars. I guess that it is a quite common feature.
I have managed to find a command that locks single bars via :
toolBar->setMovable(false);
But I cannot figure out how to lock all toolbars.
Edit
This question used to contain an inquiry concerning the toolbar context menu rather than the standard menu. Since I got an answer concerning the context menu elsewhere I removed it from this question.
How to add an entry to toolbar context menu in qt?
Here is an example of how you can achieve it. First, add a QAction and a QMenu; also, declare all your toolbars private :
private:
QMenu* m_pLockMenu;
QToolBar* m_pFileToolBar;
QToolBar* m_pEditToolBar;
QToolBar* m_pHelpToolBar;
QAction* m_pLockAction;
Also, declare a slot where you will manage the locking of your toolbars when the action will be triggered :
public slots :
void lockActionTriggered();
Implement your slot. You just need to lock all the toolbars :
void lockActionTriggered()
{
m_pFileToolBar->setMovable(false);
m_pEditToolbar->setMovable(false);
m_pHelpToolBar->setMovable(false);
}
Now, you just have to declare your main window in your .cpp, and add the menu, the toolbars and the action in it :
QMainWindow* mainWindow = new QMainWindow();
m_pLockMenu = mainWindow->menuBar()->addMenu("Lock Toolbars");
m_pFileToolBar = mainWindow->addToolBar("File");
m_pEditToolBar = mainWindow->addToolBar("Edit");
m_pHelpToolBar = mainWindow->addToolBar("Help");
m_pLockAction = new QAction("Lock", this);
Now, add the action to the menu :
m_pLockMenu->addAction(m_pLockAction);
And connect the QAction's signal triggered() to your slot :
connect(m_pLockAction, SIGNAL(triggered()), this, SLOT(lockActionTriggered()));
Don't forget to show() your main window :
mainWindow->show();
And it should be working now!
EDIT
Your code must look like this :
In the mainwindow.h :
class MainWindow : public QMainWindow
{
...
private:
QMenu* m_pLockMenu;
QToolBar* m_pFileToolBar;
QToolBar* m_pEditToolBar;
QToolBar* m_pHelpToolBar;
QAction* m_pLockAction;
public slots :
void lockActionTriggered();
};
In the main.cpp:
int main(int argc, char *argv[])
{
...
QApplication app(argc, argv);
MainWindow window;
window.show();
app.exec();
}
In the mainwindow.cpp:
void MainWindow::createActions()
{
m_pLockMenu = menuBar()->addMenu("Lock Toolbars");
m_pFileToolBar = addToolBar("File");
m_pEditToolBar = addToolBar("Edit");
m_pHelpToolBar = addToolBar("Help");
m_pLockAction = new QAction("Lock", this);
m_pLockMenu->addAction(m_pLockAction);
connect(m_pLockAction, SIGNAL(triggered()), this, SLOT(lockActionTriggered()));
...
}
void MainWindow::lockActionTriggered()
{
m_pFileToolBar->setMovable(false);
m_pEditToolbar->setMovable(false);
m_pHelpToolBar->setMovable(false);
}
If you have a pointer to your mainwindow, you can simply find all the toolbars and iterate over them:
// in slot
for (auto *t: mainWindow->findChildren<QToolBar*>())
t->setMovable(false);
Alternatively, you might want to connect all toolbars to a single toggle action, when you initialise the UI:
// in constructor
for (auto *t: this->findChildren<QToolBar*>())
connect(action, &QAction::toggled, t, &QToolBar::setMovable);
One common example with flexible lock options
# Created by BaiJiFeiLong#gmail.com at 2022/2/15 22:56
import typing
from PySide2 import QtWidgets, QtGui, QtCore
class Window(QtWidgets.QMainWindow):
def createPopupMenu(self) -> QtWidgets.QMenu:
menu = super().createPopupMenu()
menu.addSeparator()
toolBars: typing.Sequence[QtWidgets.QToolBar] = self.findChildren(QtWidgets.QToolBar)
for toolbar in toolBars:
if toolbar.rect().contains(toolbar.mapFromGlobal(QtGui.QCursor.pos())):
title = "%s %s" % ("Lock" if toolbar.isMovable() else "Unlock", toolbar.windowTitle())
menu.addAction(title, lambda toolbar=toolbar: toolbar.setMovable(not toolbar.isMovable()))
menu.addSeparator()
if any(x.isMovable() for x in toolBars):
menu.addAction("Lock All", lambda: list(x.setMovable(False) for x in toolBars))
if any(not x.isMovable() for x in toolBars):
menu.addAction("Unlock All", lambda: list(x.setMovable(True) for x in toolBars))
return menu
app = QtWidgets.QApplication()
window = Window()
window.setWindowTitle("Toolbar Example")
for i in range(1, 6):
toolBar = window.addToolBar(f"ToolBar{i}")
toolBar.setMovable(i % 2 == 0)
toolBar.addWidget(QtWidgets.QPushButton(f"ToolBar {i}"))
label = QtWidgets.QLabel("Ready")
label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
window.setCentralWidget(label)
window.resize(800, 600)
window.show()
app.exec_()

Qt: How to set "?" button for a QWidget?

In a QWidget like QLabel, how can we set a "?" button, such that when clicked (or hovered) it should show some help text.
Also you can use QMenu instead of QPushButton + QLabel.
// Constructor
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotCustomMenu(QPoint)));
// slotCustomMenu(QPoint)
QMenu menu(this);
menu.addAction(this->toolTip());
menu.addAction(this->whatsThis());
menu.exec(QCursor::pos());
Easiest way to show help when hover QWidget: setToolTip(QString) and setToolTipDuration(int).
If you want a "?" button, just implement your own QWidget. Then via ui designer or directly in your code add QPushButton and QLabel on layout, and show your QLabel with help text in position of cursor when clicked(). Something like this:
{
// Constructor
...
m_mainLabel = new QLabel("Main text");
m_button = new QPushButton("?");
m_helpLabel = new QLabel("Help text");
connect(m_button, SIGNAL(clicked(bool)),
this, SLOT(slotShowOrHideHelpLabel(bool)));
QHBoxLayout *hBoxLayout = new QHBoxLayout;
hBoxLayout->addWidget(m_mainLabel);
hBoxLayout->addWidget(m_button);
setLayout(hBoxLayout);
}
void slotShowOrHideHelpLabel(bool showHelpLabel)
{
if (showHelpLabel)
{
m_helpLabel->show();
m_helpLabel->move(QCursor::pos());
}
else
{
m_helpLabel->hide();
}
}

how to use mousePressEvent on QPushButtons

I've made some QPushbuttons like QPushButton **btn and I want to know when the user clicks on one of them using QMouseEvent here is the code but this idea does not work at all any ideas??
void Game::mousePressEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::LeftButton)
{
btn[ev->x()][ev->y()].setStyleSheet("background-color : black;");
}
else
{
btn[ev->x()][ev->y()].setStyleSheet("background-color : red;");
}
that else part is for right click
and here is the code that generates the buttons
void Game::MakeButton()
{
btn = new ApButton*[column];
hrztl = new QHBoxLayout[column];
hrztl->setSpacing(0);
for(int i=0; i<column;i++)
{
btn[i] = new ApButton[row];
for(int j=0; j<row; j++)
{
btn[i][j].setRowCol(i,j);
btn[i][j].setFixedSize(50,50);
hrztl[i].addWidget(&btn[i][j]);
}
ui->MainLayout->addLayout(&hrztl[i]);
}
ui->MainLayout->setSpacing(0);
}
ApButton is a class that inherits QPushButton
This is a good example of use for a QSignalMapper, as seen there: http://qt-project.org/doc/qt-5.0/qtcore/qsignalmapper.html#details
ButtonWidget::ButtonWidget(QStringList texts, QWidget *parent)
: QWidget(parent)
{
signalMapper = new QSignalMapper(this);
QGridLayout *gridLayout = new QGridLayout;
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button, texts[i]);
gridLayout->addWidget(button, i / 3, i % 3);
}
connect(signalMapper, SIGNAL(mapped(QString)),
this, SIGNAL(clicked(QString)));
setLayout(gridLayout);
}
In that example, every button is identified by its title, as a QString. The mapper allows you to retrieve the corresponding button's title when one of them is clicked.
Switch your
Game::mousePressEvent(QMouseEvent *e)
to
ApButton::mousePressEvent(QMouseEvent *e)
since you are trying to implement the Press Event of the Button. If you only want to have the moment of the button being pressed and not changing Button behaviour with this, use a SIGNAL/SLOT connection instead of reimplementing the event (add to your creation):
connect(btn[i][j], SIGNAL(pressed()), this, SLOT(slotButtonPressed());
void Game::slotButtonPressed(){
//doSomething
}
use a QButtonGroup or the QSignalMapper if you need to identify more then one Button in a single method or use QObject::sender(), but this can be tricky sometimes.
I had a similar situations some times ago.. I had a QDialog and I had to dinamically add some QPushButton.. then I need to know on which button the user pressed.. so I needed something like:
connect( btn, SIGNAL( clicked(int) ),
this, SLOT( handle(int) ));
for instance a signal-slot connection with the id of the clicked button and a function for handle the click. The function is the same for each buttons and can handle the specific button because of the id..
Implementing this is quite simple subclassing QPushButton adding an id and a new signal..
Hope it's some help!
If Apbutton inherits QPushButton, why don't connect to clicked()?
then you can call QObject::sender()
On slot:
ApButton *but = dynamic_cast<ApButton*>QObject::sender()
if(but)
{
but->setStyleSheet("background-color : black;");
}
to get the clicked buttonbutton and set its stylesheet

QDialog not closing right away when pressing the X, how to make it NOT on top?

I open QDialog window from QMainWindow. Now when I press the QDialog window
its not always closing in the first press - I need to press few times (3-4) to close it .
I have closeEvent slot that has simple event->accept(); inside it.
This is how I call the QDialog from the main window:
void MyManager::DialogContainerOpen(type t)
{
if(pMyDialogContainer == NULL)
{
pMyDialogContainer = new MyDialogContainer();
}
int returnVal = QDialog::Rejected;
if(!m_bContainer)
{
m_bContainer = true;
int returnVal = pMyDialogContainer->exec();
if(returnVal != QDialog::Accepted ) {
m_bContainer = false;
}
}
}
This is the first problem.
The second problem is how do i set the QDialog windows NOT to be allays on top? (I don’t want it to block the parent window.
UPDATE
well i found out that the function from the MainWindow that showing the contexMenu
and inside it has the connect single/slot is keeps to invoke so i just used the disconnect
i dont know if its the best sulotion but its working.
now i juat have the final problem .
here is the code i hope its ok
void MainWindowContainer::ShowContextMenu(const QPoint& pos) // this is a slot
{
QModelIndex modelIndx;
QPoint globalPos = ui.treeView_mainwindow->mapToGlobal(pos);
bool b1 = connect(OpenAction, SIGNAL(triggered()),m_SignalMapper, SLOT(map()) );
m_SignalMapper->setMapping(OpenAction,voidID);
bool b2 = connect(m_SignalMapper, SIGNAL(mapped(QString)), this, SLOT(OpenWin(QString)));
QAction* selectedItem = ContextMenu.exec(globalPos);
}
void MainWindowContainer::OpenWin(QString gid)
{
//disconnect(sender0, SIGNAL(overflow()),receiver1, SLOT(handleMathError()));
disconnect(m_SignalMapper, SIGNAL(mapped(QString)),this, SLOT(OpenWin(QString)));
disconnect(OpenAction,SIGNAL(triggered()),m_SignalMapper, SLOT(map()));
....
....
}
For your second question, the term you are looking for is modal vs modeless dialogs. The QDialog documentation tells exactly how you create non-modal dialogs:
Modeless dialogs are displayed using show(), which returns control to the caller immediately.
i.e. don't use exec() as that will make a modal dialog (which blocks the parent).
You should not connect the same signal/slot more than once unless you want the action run multiple times. All you need to do is to connect the QAction's signal to the slot once. This is usually done in the constructor (or a dedicated function called from the constructor) where you create the action.