How can I disable Alt + F4 window closing using Qt? - qt

I've disabled X button in Qt from my dialog using this line:
myDialog->setWindowFlags(Qt::Dialog | Qt::Desktop)
but I couldn't detect Alt + F4 using this code:
void myClass::keyPressEvent(QKeyEvent *e)
{
if ((e->key()==Qt::Key_F4) && (e->modifiers()==Qt::AltModifier))
doSomething();
}
what should I do to detect Alt+F4 or disable it in Qt?

Pressing Alt+F4 results in a close event being sent to your top level window. In your window class, you can override closeEvent() to ignore it and prevent your application from closing.
void MainWindow::closeEvent(QCloseEvent * event)
{
event->ignore();
}
If you left the close button (X) visible, this method would also disable it from closing your app.
This is usually used to give the application a chance to decide if it wants to close or not or ask the user by displaying an "Are you sure?" message box.

The code below prevents a dialog close when pressed Alt+F4, [X] or Escape, but not by calling SomeDialog::close() method.
void SomeDialog::closeEvent(QCloseEvent *evt) {
evt->setAccepted( !evt->spontaneous() );
}
void SomeDialog::keyPressEvent(QKeyEvent *evt) {
// must be overridden but empty if the only you need is to prevent closing by Escape
}
good luck to all of us ;)

Also you can handle the event in your dialog's class (at least if it's modal dlg):
void MyDialog::closeEvent(QCloseEvent* e)
{
if ( condition )
e->ignore();
else
__super::closeEvent(e);
}

Related

QWidget not closing - leaving empty window

I have a problem with a QWidget derivate (NewPayment). It's a simple window, with some controls and a QDialogButtonBox . It has 2 slots:
void NewPayment::on_buttonBox_accepted() {
//(some action going in here)
this->close();
}
void NewPayment::on_buttonBox_rejected() {
this->close();
}
When I click either OK or Cancel - the slot is triggered as expected. The problem is, that the window does not close. All the contents dissappears, and an empty window is left (window title is left).
The widget exists as a MDISubwindow, and is created like so:
void HurBudClientGUI::addNewPayment(int direction, int contractorid) {
foreach(QMdiSubWindow* it, this->ui.mainArea->subWindowList()) {
if ( NewPayment* np = qobject_cast<NewPayment*>( it->widget() ) ) {
if (np->getContractorID() == contractorid) {
this->ui.mainArea->setActiveSubWindow(it);
return;
}
}
}
NewPayment* np = new NewPayment(direction, contractorid, this);
np->setAttribute(Qt::WA_DeleteOnClose);
this->ui.mainArea->addSubWindow(np);
np->show();
}
The interesting part is, that when I either:
click on the 'X' in tre upper right corner
call QMdiArea::closeActiveSubWindow() from the main window
call QMdiArea::closeAllSubWindows() from the main window
the window is closed properly. I have overwritten a QWidget::closeEvent(QCloseEvent * event) for my class:
void NewPayment::closeEvent(QCloseEvent * event) {
qDebug() << "[" << __FUNCTION__ << "]:" << "event: " << event << "; sender:" << sender();
}
and it shows preety much the same event every time - no matter how I try to close it:
[ NewPayment::closeEvent ]: event: QCloseEvent(Close, 0x40bd64, type = 19) ; sender: QDialogButtonBox(0x4dfa7a8, name = "buttonBox") // I hit cancel
[ NewPayment::closeEvent ]: event: QCloseEvent(Close, 0x40b634, type = 19) ; sender: QObject(0x0) // I hit the 'X' in the window corner
[ NewPayment::closeEvent ]: event: QCloseEvent(Close, 0x40b468, type = 19) ; sender: QObject(0x0) // I hit "close active sub window" from parent window
[ NewPayment::closeEvent ]: event: QCloseEvent(Close, 0x40b454, type = 19) ; sender: QObject(0x0) // I hit "close all sub windows" from parent window
The best part is, that when I hit "cancel" (the windows is cleared, but stays open), and then click "X" or whatever - the window is closed, but the control does not pass through my NewPayment::closeEvent (i have a brakepoint there - and it does not fire) .
It works preety much the same in other windows. What is strange, that I'm preety sure that it worked previously (+- a week ago) for other windows (they closed after clicking OK ant performing all necessary operations) . I guess I will end up analyzyig diff from SVN, but maybe someone had similar issue? I have had very little sleep lately, so maybe I missed something trivial?
I will appreciate any help.
What do you expect, a widget is not a window. You get output from closing the widget, but that's not the same as closing the window.
You need to have a handle to the window if you want to close it. You could:
keep the pointer returned from addSubWindow()
create the window in advance, create the widget parented to the window, set the window's widget to the widget, and then use the widget's parent() to access the window.
I followed #ddriver 's suggestion and ended up with
void NewPayment::on_buttonBox_rejected() {
if (QMdiSubWindow* psw = qobject_cast<QMdiSubWindow*>(this->parent()) ) {
psw->close();
} else {
this->close();
}
}
Now it works as it was supposed to.

Qt checkbox stateChanged event handler

In my Qt application, I want to use a checkbox to do A when it's toggled to unchecked, and do B when toggle to checked. The checkbox is hooked to foo(int).
connect(myCB, SIGNAL(stateChanged(int)), this, SLOT(foo(int)));
There's a problem when the sanity check fails (eg. some variable got invalid values), I want to just show error message and remain everything unchanged. So I toggle the checkbox again to revert it back to where it was. But it seems this action would trigger the callback function foo(int) again, which mess up everything. I don't want it to trigger the callback in this situation. How should I do? Or is there a better way? See the pseudo code below.
void foo(int checkState)
{
if (checkState == Qt::Unchecked) {
if (!passSanityCheck()) {
// show error message
checkBoxHandle->toggle();
return;
}
// do A when it's unchecked
}
else {
if (!passSanityCheck()) {
// show error message
checkBoxHandle->toggle();
return;
}
// do B when it's checked
}
return;
}
Connect QCheckBox::clicked(bool checked) signal to your slot:
QCheckBox *cb = new QCheckBox(this);
connect(cb, SIGNAL(clicked(bool)), this, SLOT(toggled(bool)));
This signal is not emitted if you call setDown(), setChecked() or toggle().

in Qt, what QEvent means loses window focus, regain window focus? (Set transparency)

I need to set transparency when my application loses focus.
I also need to reset the transparency when it regains focus (from a mouse click or alt-tab or whatever)
I know how to set the transparency, so that is not the issue:
setWindowOpacity(0.75);
The issue is WHEN?
I agree with Kévin Renella that there are sometimes issues with QWidget::focusInEvent and QWidget::focusOutEvent. Instead, a better approach would be to implement QWidget::changeEvent():
void MyQWidget::changeEvent(QEvent *event)
{
QWidget::changeEvent(event);
if (event->type() == QEvent::ActivationChange)
{
if(this->isActiveWindow())
{
// widget is now active
}
else
{
// widget is now inactive
}
}
}
You can also achieve the same thing by installing an event-filter. See The Event System on Qt Documentation for more information.
When a QFocusEvent event occurs. Just re-implement
void QWidget::focusInEvent ( QFocusEvent * event );
void QWidget::focusOutEvent ( QFocusEvent * event );
from QWidget. Make sure to always call the super-class method before or after doing your work. i.e., (before case)
void Mywidget::focusInEvent (QFocusEvent * event ){
QWidget::focusInEvent(event);
// your code
}
But, there are sometimes issues with QWidget::focusInEvent and QWidget::focusOutEvent. See this answer for a more reliable approach.
There are sometimes issues with QWidget::focusInEvent and QWidget::focusOutEvent events of QWidget
There is an alternative using QWidget::windowActivationChange(bool state). True, your widget is active, false otherwise.

QTableView mouseRelease event not called when drag ends, bug?

I would simply like to catch the mouseRelease event when a user drags an item from a QTableView and releases the left button.
I want to highlight possible dropping zones in my app, like changing the background of a widget.
I start by detecting the drag-start by re-implementing:
void LibraryTableView::startDrag( Qt::DropActions supportedActions )
{
m_dragReleased = false;
emit dragStart();
QTableView::startDrag(supportedActions);
}
and emitting my own signal.
Now that the dropzone has changed, I need to catch the release event to redraw the dropzone as before whether the drag and drop succeded or not !
I tried different models, reimplementing the 4 mouse events and eventFilter, but the Mouse Release Event is never catched.
Here is my code:
void LibraryTableView::mouseDoubleClickEvent( QMouseEvent* event )
{
QTableView::mouseDoubleClickEvent(event);
}
void LibraryTableView::mouseMoveEvent( QMouseEvent* event )
{
qDebug() << "move";
QTableView::mouseMoveEvent(event);
}
void LibraryTableView::mousePressEvent( QMouseEvent* event )
{
qDebug() << "press";
QTableView::mousePressEvent(event);
}
void LibraryTableView::mouseReleaseEvent( QMouseEvent* event )
{
qDebug() << "real"; // Never called when drag ends ...
QTableView::mouseReleaseEvent(event);
}
So, it is a bug ?
If you know a trick, it would help me a lot.
Thanks !
Edit: I cannot reimplement dropEvent for every widget in my application, if the user drags and drop an element in another application, I still want to catch the release event ...
As said above it's been 3 years but thank to the last answer I found an even easier solution for this problem.
void LibraryTableView::startDrag( Qt::DropActions supportedActions )
{
m_dragReleased = false;
emit dragStart();
QTableView::startDrag(supportedActions);
//CODE HERE WILL BE EXECUTED ONLY WHEN THE MOUSE BUTTON HAS
//BEEN RELEASED SO YOU CAN DO THE FOLLOWING
emit dragStop();
}
Three years since this question was asked and this Qt problem still exists in Qt 5.4. Lately I had the same problem: Drops outside the application and no MouseReleaseEvent. The solution is simple and not really a trick:
The mousePressEvent, which starts the drag&drop looks like this (simplified):
void DragNDropListView::mousePressEvent(QMouseEvent *event){
....
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
mimeData->setData("application/x-xxxxxx", QByteArray());
drag->setMimeData(mimeData);
drag->exec();
// The d&d ended here. Inside the widget where the drag
// started, a mouseReleaseEvent would have been fired.
// Outside this widget not.
// drag->mimeData() is here still available.
}
}
}
The trick is simple: drag->exec() starts its own event loop, which is exited when the mouse button is released. The mouse position after drag->exec(); can be determined with QCursor.
For QTableView you have to reimplement three function for dnd support:
void dragEnterEvent ( QDragEnterEvent * event ) - in this function the mouse enters the widget
void QAbstractItemView::dragMoveEvent ( QDragMoveEvent * event ) - in this function you can update your drop zone highlighting
void QAbstractItemView::dropEvent ( QDropEvent * event ) - in this function you decide whether to accept the event
I encountered a similar issue and was not happy to find out that the MouseReleaseEvent was not getting fired at the end of a drag.
I just used the DragLeaveEvent and toggled my variables off, as I would have done in the MouseReleaseEvent. If user dragged off the app, and then back on, those previously toggled off variables would get re-enabled in the DragMoveEvent (assuming it is accepted).
That was my trick, at least. Hope it helps.

How to tell the mouse button using QApplication::mouseButtons() in a "click" slot?

I have a QMainWindow, and want to handle the "clicked" signal from a smaller widget (such as tableview) inside it.
Originally I connect the signal to a slot of this QMainWindow, this is the most common approach.
Now I need to tell which mouse button is clicked, and do different things for left and right button, I found that the "clicked" signal don't have the mouse event information.
I tried to implement the "mousePressEvent" function,but there are still some problem. if the mouse action is acted on the smaller widget, the MainWindow won't go into its mousePressEvent.
Some document says that we can tell the button by QQApplication::mousebuttons()
http://bugreports.qt-project.org/browse/QTBUG-1067
and I also found some sample code. However, this is for "press event", but I want to get the mouse button for "click event".
Follows is the sample code :
connect(moduleTree,SIGNAL(itemPressed(QTreeWidgetItem *, int)),this,SLOT(SlotItemClicked(QTreeWidgetItem *, int)));
void CGuiMainwindow::SlotItemClicked(QTreeWidgetItem *item, int column)
{
if (qApp->mouseButtons() == Qt::LeftButton)
{ return; }
if (qApp->mouseButtons() == Qt::RightButton)
{
......
}
}
When I try to do this, neither of the 2 if statements will be satisfied, I don't know why. the qApp->mouseButtons() always return 0, how can I get the clicked mouse button by QApplication::mouseButtons?
In my code, the slot looks like that :
void clickItem( const QModelIndex & idx){.....}
You get 0 becouse clicked is emited after mouse release, not at mouse press. What do you want to achieve ? Maybe try settings on you widget contextMenuPolicy to custom, and than connect to signal contextMenuRequested (for the right click) and clicked for the left click ?
for "connect" use this:
connect(moduleTree,SIGNAL(itemClicked(QTreeWidgetItem *,int )),this
,SLOT(SlotItemClicked(QTreeWidgetItem *, int)));
define a global flag:
public:
Qt::MouseButton mouseClickedBtnFlag;
and then reimplement "mouseReleaseEvent":
CGuiMainwindow::mouseReleaseEvent ( QMouseEvent * event )
{
mouseClickedBtnFlag = event->button();
}
and then:
void CGuiMainwindow::SlotItemClicked(QTreeWidgetItem *item, int column)
{
if (mouseClickedBtnFlag == Qt::LeftButton)
{ return; }
if (mouseClickedBtnFlag == Qt::RightButton)
{
......
}
}
Qt::MouseButtons is a QFlags type. You can't test it with == operator. Use & operator for testing:
if(QApplication::mouseButtons() & Qt:LeftButton) {
...
}

Resources