QT , my form was hidden after calling setWindowFlags() in my slots - qt

I just want to disable form's close button while doing a task(by QThread), So I connected the thread's signal "started()" and "finished()" to my two slots, for controlling my form's close button.
//...
m_pTestThread = new TestThread();
connect(m_pTestThread, SIGNAL(started()), this, SLOT(onThreadStart()));
connect(m_pTestThread, SIGNAL(finished()), this, SLOT(onThreadFinish()));
m_pTestThread->start();
//...
void QTest::onThreadStart()
{
this->setWindowFlags(this->windowFlags() & (~Qt::WindowCloseButtonHint));
}
void QTest::onThreadFinish()
{
this->setWindowFlags(this->windowFlags() | Qt::WindowCloseButtonHint);
}
After the thread started, my form was hidden... that is strange.
So I call show() after setWindowFlags() function to avoid this problem,
but still don't know why this happened...
Is this the expected behaviour? Should I call show() after setWindowFlags()?

Check the documentation for setWindowFlags here:
Note: This function calls setParent() when changing the flags for a
window, causing the widget to be hidden. You must call show() to make
the widget visible again..

Related

How to find subsequent (all) SLOT from a subclass

I need to block specific buttons on an MMI.
I implemented a button blocking function in a subclass of QPushButton.
For this, I used the clicked() signal and blocked the button with blockSignals(true).
This means that with each button clicked on my MMI, 2 SLOTS are always called.
But when calling the blocking of a specific button, I get the first SLOT (clicked()) of my subclass, in which I block the button, then I then arrive in the original SLOT linked to this button, which is still called despite the blocking (the first time only).
How can I in my QPushButton subclass know the subsequent SLOTs linked to this button and avoid them (delete them)?
void QbtnStandardButton::slotButtonClicked(void)
{
if (modeProtection)
{
// Special mode to protect/unprotect the button
if (isProtected())
{
// Reset the protection
this->blockSignals(false);
}
else
{
// Set the protection: button will be unclickable
this->blockSignals(true);
}
modeProtection = false;
}
if (isProtected())
{
QMessageBox *pMsgBox = new QMessageBox(QMessageBox::Information,
"Protection",
"This button is protected!",
QMessageBox::Ok);
pMsgBox->exec();
pMsgBox->deleteLater();
// Here: remove subsequent SLOT of this button ?
}
}
I think it's very difficult if not impossible to find SLOTS linked to a button.
I worked around the problem by using an eventFilter() instead of a SIGNAL() in my base class.
In this case, I can filter the "clicked()" event before it is reissued.

Triggering an action based on its custom shortcut

Suppose I have some action to happen. For that I can create a QAction object and connect its triggered() signal to the slot that executes the desired function. Also, I can have a shortcut associated with the action; by changing the shortcut I'll be able to execute the same action with that shortcut.
My problem now is that the "shortcut" I wanna set to the action, contains also a mouse button press (and mouse events cannot be assigned to action shortcuts); say I want Shift+Left mouse button. Maybe this sounds a little bit harsh but bear with me.
What do I need? Well, I have a button, and an action (say "execute a script"). I want the script to execute when Shift+Left click is clicked, and I want this "shortcut" to be customized, i.e. the user should be able to change to shortcut to, say Ctrl+Left click (from some GUI element, e.g. button text), and now Ctrl+Left click should execute the script.
How can I achieve this?
Note: I as a user would expect an action triggered by a mouse button to be position dependent. If so, the following gets a bit simpler.
Qt doesn't have an option to specify such a shortcut.
You can roll your own by reacting to mouse events:
Maybe you have an event handler mousePressEvent(),
or a generic eventFilter(QObject *obj, QEvent *evt),
or utilize QApplication::notify
Whichever, at some place you need to catch a QMouseEvent *mouseEvt.
Choose the widget (or qApp) that is as outmost as needed.
There, compare mouseEvt->button() and mouseEvt->modifiers() to your list of actions and trigger the selected action. When the user chooses another trigger method, adjust your list of actions.
Let's put this to practice:
class MainWindow : public QWidget {
Q_OBJECT
public:
QMap<QPair<Qt::MouseButton, Qt::KeyboardModifiers>, QAction*> mapMouseShortcuts;
QAction *pLaunchScript;
MainWindow() : QWidget() {
mapMouseShortcuts.insert(qMakePair(Qt::LeftButton, Qt::ControlModifier), pLaunchScript);
}
void mousePressEvent(QMouseEvent *me) {
QAction *action = mapMouseShortcuts.value(qMakePair(me->button(), me->modifiers()), Q_NULLPTR);
if(action != Q_NULLPTR) {
action->trigger();
me->accept(); // optional
}
// optional:
if(!me->isAccepted()) {
QWidget::mousePressEvent(me);
}
}
};

Using the closeEvent in a qt application does not close it

I am learning qt, and experimenting with examples from a textbook.
The original textbook code has the following, set up to save and close on the x button:
void MainWindow::closeEvent(QCloseEvent *event)
{
if (okToContinue()) {
writeSettings();
event->accept();
} else {
event->ignore();
}
}
i experimented with a simple exit in its menu - and it works:
void MainWindow::close()
{
if (okToContinue()) {
QApplication::quit();
}
}
But I want to take advantage of the already written closeEvent, so i replaced the code above with
void MainWindow::close()
{
QCloseEvent *event = new QCloseEvent();
closeEvent(event);
}
I get the checking for changes and saving app, implemented through the okToContinue function. But the application does not close.
i tried to follow through debugging and.. with my small understanding, it seems that there is a close signal being sent...
I don't have a good understanding of this, can somebody please help me figure out what am i doing wrong and how to fix it ?
(the sample code is from C++ GUI Programming with Qt 4, chapter 3)
You don't have to reimplement MainWindow::close() in your subclass.
From the Qt Docs:
...QCloseEvent sent when you call QWidget::close() to close a widget
programmatically...
So you just have to reimplement MainWindow::closeEvent(QCloseEvent *event) if you want to control this event.
This event fires when you click x or call close() from the code.
The closeEvent and related methods don't actually execute the action that happens when a given event is received. They merely allow you to act on the event and perhaps disable its further processing. The closing of the window is done within QWidget::event, where closeEvent is called from.

Qt - Close subMenu with signal/slot

I have a Qt main window where I call another window, actually a kind of submenu wich contains parameters for the first one; here is a part of this main window :
void Ui_MainWindow::createSignals()
{
connect(actionDisk_galaxy, SIGNAL(triggered()), this, SLOT(ICMenu()));
}
void Ui_MainWindow::ICMenu()
{
qmenu = new QMainWindow;
DiskMenu = new Ui_DiskGalMenu;
DiskMenu->setupUi(qmenu,this);
setInitialDiskMenuPosition(qmenu, this);
qmenu->show();
}
As you can see, I call another QMainwindow ("qmenu"); here's the code of this new window (whose type is "Ui_DiskGalMenu"):
void Ui_DiskGalMenu::createMenuSignals()
{
connect(pushButton_4, SIGNAL(clicked()), this, SLOT(closeMenu()));
}
void Ui_DiskGalMenu::closeMenu()
{
close(true);
}
After setting parameters in this sub-menu, I would like to close it with a pushButton (here "pushButton_4").
My problem is that when I click on "pushButton_4", this window doesn't close.
I have also tried to reimplement closeEvent but without success.
This function call looks like a mistake:
close(true);
QWidget::close() doesn't take any parameters. So what you're doing here, is call the close(int) function of the C library (for closing file descriptors.) bool is implicitly converted to int, so you end up with this call:
::close(1);
Which is (probably) closing stderr.
You can see what's happening if you change the above to:
this->close(true);
You should get a compilation error since no such function exists. So the correct call would have been:
this->close();
However, QWidget::close() is already a slot, so you don't need the Ui_DiskGalMenu::closeMenu() function at all. All you need is connect to the close() slot to begin with:
connect(actionDisk_galaxy, SIGNAL(triggered()), this, SLOT(close()));
If you need to do more stuff when the window closes, you can override closeEvent() which will be called before the window gets closed.

Cannot change cursor in Qt main window from menu action

In my MainWindow, I have a push button and a menu bar item whose signals are both connected to the same slot. In the slot function, I have written:
mainWindow->setCursor(QCursor(Qt::WaitCursor));
This works as expected when the slot function is invoked via the button; however, when the same function is invoked from the menu, the wait cursor doesn't appear. Any idea why?
I also considered using QApplication::setOverrideCursor; however, that causes other problems.
Any recommendations? Thanks!
(I am using Qt 4.7 and doing my development on Windows 7 using Qt Creator with the default MinGW compiler.)
Here's more detail.
in MainWindow constructor: this->setCursor(Qt::CrossCursor);
signal/slot connections:
QObject::connect(button, SIGNAL(clicked()), MainWindow, SLOT(showMessageBox()));
QObject::connect(action, SIGNAL(triggered()), MainWindow, SLOT(showMessageBox()));
showMessageBox function:
void MainWindow::showMessageBox()
{
this->setCursor(Qt::WaitCursor);
// display wait cursor briefly before showing message box
for (int i = 0; i < 1<<30; ) {++i;}
QMessageBox msgBox;
msgBox.setText("Hello!");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setCursor(Qt::PointingHandCursor);
msgBox.exec();
this->setCursor(Qt::CrossCursor);
}
When showMessageBox is invoked with 'button', the wait cursor is displayed as expected.
When showMessageBox is invoked through 'action', the wait cursor does not appear; instead the cursor changes from Qt::CrossCursor to a Qt::ArrowCursor as soon as the user selects the 'action' menu item, and then changes to Qt::PointingHandCursor once the message box opens. The wait cursor never appears.
Your code is synchronous and uses a delay loop. When you're in the delay loop, there's no way for any Qt code to execute. A cursor change requires the event loop to be spinning -- so it appears from the symptoms you give.
Here's how to do it correctly -- remember, if you use delays/sleeps and other blocking calls in your GUI code, your users will hate you, and rightly so. Using exec() in message/dialog boxes is also bad style. Your application is asynchronous, code it so. Make sure your slots are declared as such (in the protected slots: section of MainWindow declaration).
void MainWindow::showMessageBox()
{
this->setCursor(Qt::WaitCursor);
QTimer::singleSlot(200, this, SLOT(slot1()); // fire slot1 after 200ms
}
void MainWindow::slot1()
{
QMessageBox * msgBox = new QMessageBox(this);
msgBox->setText("Hello!");
msgBox->setStandardButtons(QMessageBox::Ok);
msgBox->setCursor(Qt::PointingHandCursor);
msgBox->show();
connect(msgBox, buttonClicked(QAbstractButton*), SLOT(slot2(QAbstractButton*)));
}
void MainWindow::slot2(QAbstractButton* button)
{
// a button was clicked on the message box
this->setCursor(Qt::CrossCursor);
}

Resources