Main widget steals focus after execution QAction.
I need the focus to be set to popup widget.
QAction *action = new QAction(tr("show popup"), this);
connect(action, &QAction::triggered, this, &MyWidget::showPopup);
addAction(action);
void MyWidget::showPopup()
{
QMessageBox* popup = new QMessageBox(this);
popup->setModal(true);
popup->show();
popup->setFocus();
}
MyWidget inherits from QWidget.
Because you just created popup, it's not 'there' yet in the GUI. Even the show() doesn't instantly show it. After you leave the scope of MyWidget::showPopup(), the GUI event loop will continue looping and be able to process your new popup. Thus the setFocus() call comes too early.
But there is help underway:
QWidget::setFocus() is a slot, so you can invoke it.
If you use a timer (QTimer::singleShot(0, popup, SLOT(setFocus()));), it should work.
Maybe you'll need to use 10ms instead of 0ms.
Related
I have a QAction in QMenu. When QAction is triggered() I would like to know which button did it.
connect(YourAction, SIGNAL(triggered()), this, SLOT(actionclicked()));
void MainWindow::actionclicked(QMouseEvent *e)
{
if (e->buttons() == Qt::RightButton)
}
I can't do something like this because triggered() does not have such argument.
As #mvidelgauz noticed, QAction is abstracted from input devices which may triggered the action. Nevertheless, if the action is used in your GUI, it has one or more associated widgets: tool buttons in a toolbar, entries in menu bar and so on. These widgets act like any other widgets, so they receive events which may be filtered with the use of installEventFilter and eventFilter. These two methods are inherited from QObject, so they are present in almost any Qt class. For example, let's create an application with QMainWindow and QAction called actionTest. Then let's turn the main window itself into an action filter for actionTest's associated widgets by overriding main window's eventFilter method:
bool eventFilter(QObject *obj, QEvent *ev) {
//Catch only mouse press events.
if(ev->type() == QEvent::MouseButtonPress) {
// Cast general event to mouse event.
QMouseEvent *mev = static_cast<QMouseEvent*>(ev);
// Show which button was clicked.
if(mev->button() == Qt::LeftButton) {
qDebug() << "Left button!";
}
if(mev->button() == Qt::RightButton) {
qDebug() << "Right button!";
}
}
// In this example we just showed the clicked button. Pass the event
// for further processing to make QAction slots work.
return QMainWindow::eventFilter(obj, ev);
}
Then we need to install event filter object for all watched objects, which are widgets in our case. Let's do it in main window constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
for(auto wgtPtr : ui->actionTest->associatedWidgets()) {
wgtPtr->installEventFilter(this);
}
}
Finally, add a slot for triggered() signal handling:
void on_actionTest_triggered() {
qDebug() << "Action triggered!";
}
Now if you click the action menu entry with left mouse button, it will print
Left button!
Action triggered!
while for right mouse button the result will be
Right button!
Action triggered!
Note that widget event filtering is always performed before triggered() signal emission.
The above code is just an example, and MainWindow class is not the best place to host eventFilter method. In real code you may either:
Create dedicated QObject subclass(es) for QAction widgets event filtering.
Subclass QAction and override it's eventFilter method. In this case you may just save the result of QMouseEvent::button() in the QAction subclass object and later use it in triggered() signal handler. There is a minor inconvenience that Qt creator (at least up to v3.2.1) does not allow you to "promote" QActions in it's form designer, so you'll need to add actions to menus manually in window constructor.
Subclass QMenu, QToolBar, etc.., and make them action filters? I don't know how can it be better than two former variants.
See also documentation about Qt event system.
Let's clarify case 2. Assume the class inherited from QAction is called MyAction. In order to make it work you need to install MyAction objects as filters for themselves (their widgets, to be more specific). You need to do it after widgets were created, so installing filter in MyAction constructor may be premature and lead to crashes. Better place for filter installation is a constructor of a class which owns MyAction object. Typically it's a widget or window class. So just add
for(auto wgtPtr : ui->myActionObject->associatedWidgets()) {
wgtPtr->installEventFilter(ui->myActionObject);
}
to your window constructor after ui->setupUi(this) call. This code is like in the above example, but we use ui->myActionObject instead of this object as filter.
triggered() cannot have this argument by design because it by itself is not necessarily result of a mouse event:
This signal is emitted when an action is activated by the user; for example, when the user clicks a menu option, toolbar button, or presses an action's shortcut key combination, or when trigger() was called
You need to connect to mouse events if you need QMouseEvent as parameter. In fact Qt itself emits triggered() when (but not only as I highlighted in doc quote) framework receives mouse event from menu. So it looks like you'll need to do a similar thing in your code and add your own logic.
P.S. This discussion might be interesting for you
I have a MainWindow and Type class.
A button in the MainWindow sends a signal to a slot with this code:
dialog = new QDialog(this);
Ui_type typeui;
typeui.setupUi(dialog);
dialog->show();
The dialog then shows. When a button is clicked on the dialog, I want to close the dialog and delete it.
I don't understand how to refer to the dialog from the dialog itself.
Any help would be appreciated. Thanks.
You can set Qt::WA_DeleteOnClose attribute on your dialog. This will ensure that the dialog gets deleted whenever it is closed.
Then call close() method in the dialog when your button is clicked.
dialog = new QDialog(this);
Ui_type typeui;
typeui.setupUi(dialog);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
Refer to the documentation for details :
QWidget::setAttribute ( Qt::WidgetAttribute attribute, bool on = true )
Qt::WidgetAttribute
First the close button is at the dialog window right, then most easy way to do it, is create a button, and connect the close() function to response the click() signal.
like:
Dialog::Dialog(){
// other code
QPushButton *closeButton = new QPushButton(tr("Close"));
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
// other code
}
Under the Qt/examples/dialog projects are good reference for your question. check it out.
The simple way to get input from a modal dialog is QDialog::exec(). This may handle everything you need.
In QML you can do the on click event. I am writing my qml in C++, however there is no onclick method.
How do you get the on click to work.
Button *btnSave = new Button();
btnSave->setText("Save");
contentContainer->add(btnSave);
Does anyone have a simple example that they could provide to get me started?
Thanks in advance.
To do this in C++, you have to connect a signal (in this case, is the Button's clicked() to a slot of your class). You better take a look here.
Supposing you defined a slot called onSaveButtonClicked() in your header, that will be called when your button is clicked:
public slots:
void onSaveButtonClicked();
in your application class, after create your button, you'd have to do:
connect(btnSave, SIGNAL(clicked()), this, SLOT(onSaveButtonClicked()));
When your button is clicked, it will emit the signal that will call the slot function.
I am developing a project using Qt4 and I have run into a slight issue.
I am creating a modal window from the main window. I want this to disable the toolbar at the top.
I have a menu item that spawns the modal from the menu. What I want is that when the modal is spawned that menus is disabled. I have tried using the setEnabled(false) function but that doesn't reset it.
Here is the code:
void Main_Screen::Create_ViPro()
{
std::auto_ptr<ViPro_Dialog> modal(new ViPro_Dialog(this));
modal->show();
modal->exec();
}
So It is just a simple class that is triggered when a menu item is selected. I feel that the problem stems from the fact that i'm setting the parent to the main screen, however I don't know how to create a modal without a parent(it doesn't make sense to do that). Is there a way to disable the parents toolbar from the child? The only thing I have seen so far is _fileMenu->setEnabled(false);
That works as long as I don't create the modal, but as soon as that is spawned, the menu works again. I'm totally lost.
Thanks in advance
Edit as Patrice
Here is the constructor
Main_Screen::Main_Screen(QWidget* parent /*= NULL*/)
: QMainWindow(parent),
_newProj(new QAction(tr("New &ViPro"), this)),
_fileMenu(menuBar()->addMenu(tr("&File")))
{
//create slot for creating a new project
connect(_newProj.get(), SIGNAL(triggered()), this, SLOT(Create_ViPro()));
_fileMenu->addAction(_newProj.get());
//if i do this then setEnabled(false) works perfectly and i can't access the menu
Create_ViPro()
}
So the function is signaled by triggering the newproject action. If i call the function directly from within the constructor it disables it as you stated patrice, however, if I have the function called via the trigger, it doesn't disable it. Am I handling the signal / slot mechanism wrong? Thanks again.
Another example, if I make the function create_vipro() as below
void Main_Screen::Create_ViPro()
{
_fileMenu->setEnabled(false);
}
The file menu isn't disabled when I trigger the event, so it must have nothing to do with the modal itself, but instead how signals are handled.
Since child is a modal dialog main screen can't react to event. But you can disable the toolbar (or menubar) before creating the modal dialog and enable it as soon as you leave the exec function:
void Main_Screen::Create_ViPro()
{
_fileMenu->setEnabled(false);
std::auto_ptr<ViPro_Dialog> modal(new ViPro_Dialog(this));
modal->show();
modal->exec(); // Will stay here until you close the modal dialog
_fileMenu->setEnabled(true);
}
if ViPro_Dialog is really a modal dialog it will works.
Another thing, since ViPro_Dialog is modal you can declare it locally without using auto_ptr:
void Main_Screen::Create_ViPro()
{
_fileMenu->setEnabled(false);
ViPro_Dialog modal(this);
modal.show();
modal.exec(); // Will stay here until you close the modal dialog
_fileMenu->setEnabled(true);
}
EDIT:
I guess (I can't test at work) that you can't enable/disable menu when it is executing a QAction. Signal is calling slots sequentially so QAction is busy when you try to disable the menu.
Try this:
In Main Screen, create a slot with one boolean parameter that enable/disable menubar. Just call the setEnabled function
In ViPro_Dialog, emit a signal with a boolean parameter (false at startup, true at validation)
In Create_ViPro, once dialog created, connect the new signal with the slot, exec dialog and don't forget to disconnect slot from signal:
void Main_Screen::Create_ViPro()
{
ViPro_Dialog modal(this);
// Connect signal/slot
modal.show();
modal.exec(); // Will stay here until you close the modal dialog
// Disconnect signal/slot
}
This can achieve what you want
EDIT2
You are doing a mistake when using modal dialog. There's a conflict between show() and exec(). When you are displaying modal dialog you don't need to disable other windows: it's automatically done by modal status of the dialog. There are many modal depth: http://qt-project.org/doc/qt-4.8/qt.html#WindowModality-enum. So your code should be:
void Main_Screen::Create_ViPro()
{
ViPro_Dialog modal(this);
// modal.setWindowModality(Qt::WindowModal); // Uncomment this line if you want to only disable parent
modal.exec();
}
Read this for more detail: http://qt-project.org/doc/qt-4.8/QDialog.html#details.
Using exec() doesn't just create a modal dialog, it also suspends most of the regular event handling, and only handles events in the dialog that is in exec(). This may include some UI updates (like the transitions from enabled to disabled), but I'm not positive. A better way to handle this might be to explicitly set the dialog modal, but allow the regular event loop to continue, something like this:
void Main_Screen::Create_ViPro()
{
ViPro_Dialog* modal = new ViPro_Dialog(this);
modal->setModal(true);
modal->show();
}
That code will still not visually disable the toolbar or menubar, but they should be unresponsive. To disable them, you could try combining this with Patrice Bernassola's answer.
I am developing an application, I have added a QToolBar object in that, and have added the QToolButton object on that, I have also connect the clicked() event with that but the problem is that the mouse click event don't work on QToolButton but when I bring focus on that using Tab, then space button works fine, but I want it with mouse click.. any idea? here is the code.
pToolBar = new QToolBar(this);
pToolBar->setAllowedAreas(Qt::NoToolBarArea);//NoToolBarAreaAllToolBarAreas
pToolBar->setFloatable(false);
pToolBar->setGeometry(300,0,160,30);
QToolButton *playButton=new QToolButton(pToolBar);
playButton->setIcon(QIcon("/images/play.png"));
playButton->setGeometry(10,0,40,30);
playButton->setToolTip("Play/Pause");
connect(playButton, SIGNAL(clicked()),SLOT(playButtonClicked()));
The Tool buttons are normally created when new QAction instances are created with QToolBar::addAction() or existing actions are added to a toolbar with QToolBar::addAction().
Example:
QAction *newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this);
newAct->setShortcut(tr("Ctrl+N"));
newAct->setStatusTip(tr("Create a new file"));
connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
fileToolBar = addToolBar(tr("File"));
fileToolBar->addAction(newAct);
You can use triggered signal, This signal is emitted when the given action is triggered.
Your example:
QToolButton *playButton=new QToolButton(pToolBar);
connect(playButton, SIGNAL(triggered()),SLOT(playButtonClicked()));
Try explicitly adding the toolbutton to the toolbar. The following code works perfectly for me:
QToolBar *pToolBar = new QToolBar(this);
QToolButton *playButton=new QToolButton(pToolBar);
playButton->setIcon(QIcon("/images/play.png"));
playButton->setText("Play");
playButton->setToolTip("Play/Pause");
playButton->setGeometry(10,0,40,30);
QAction *a = pToolBar->addWidget(playButton);
a->setVisible(true);
connect(playButton, SIGNAL(clicked()),SLOT(playButtonClicked()));
You should probably save the QAction pointer somewhere, since it's the easiest way to assign keyboard shortcuts, enable / disable the button etc. Let me know if this works for you. If it doesn't, perhaps posting a complete compilable example here will help us help you. You should be able to get a small demo program that shows your problem within one or two files.
Cheers,
As jordenysp indirectly explains, the API is QAction centric