My application's closeEvent() looks nearly like this (Qt 5.8.0 on Windows):
void MainWindow::closeEvent(QCloseEvent *event)
{
if(some_changes_were_made) // bool
{
QMessageBox mbox;
mbox.setText("Page(s) have been changed.");
mbox.setInformativeText("What do you want to do?");
mbox.addButton("Exit now", QMessageBox::AcceptRole);
mbox.addButton("Save page(s) first", QMessageBox::RejectRole);
int exit_code = mbox.exec();
if(exit_code == QDialog::Rejected)
{
// bail out of the close event so the user can save pages
event->ignore();
return;
}
}
event->accept();
}
I'm curious if the documentation is wrong, which states that exec() returns a QDialog::DialogCode. It actually seems to return the QMessageBox::ButtonRole (which interestingly is the inverse value). Or am I just doing something totally wrong here?
Please forgive any typos, as I'm unable to copy the actual code here.
Check QMessageBox reference here.
It is supposed to return one of the standardButton replies. You are using QDialogBox replies, QMessageBox has already overriden QDialogBox's exec method.
You want to check something like this:
switch (exit_code) {
case QMessageBox::Save:
// Save was clicked
break;
case QMessageBox::Discard:
// Don't Save was clicked
break;
case QMessageBox::Cancel:
// Cancel was clicked
break;
default:
// should never be reached
break;
}
Source from the same link.
Related
The first image shows what I want to do. The second one shows what I get.
I want the status bar to show the state of the special keys CAPS LOCK, NUM LOCK and SCROLL LOCK. This image is from an old project using the CStatusBar.
This snapshot is from CMainFrame class.
This image shows how I am doing it in Visual C++ 2015 MFC and the results I get. This snapshot is from CMainFrame class, too.
My question is : Can anyone tell me how my application can intercept the change from toggle buttons CAPS LOCK and NUM LOCK then update the user interface.
I tried to use this code but it doesn't work :
ON_UPDATE_COMMAND_UI(ID_INDICATOR_STYLE, &CMainFrame::OnUpdateStyle)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_FOLD, &CMainFrame::OnUpdateFold)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_OVR, &CMainFrame::OnUpdateInsert)
Thanks in advance.
First of all the standard behavior of CStatusBar is not supported by CMFCRibbonStatusBar.
The good news is that it is very easy to implement the same behavior.
Here is what you have to do in order to implement it in your application:
Add this to message map of your main frame class or child frame in case of MDI:
ON_UPDATE_COMMAND_UI(ID_INDICATOR_CAPS, &CMainFrame::OnUpdateButtonsState)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_NUM, &CMainFrame::OnUpdateButtonsState)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_SCRL, &CMainFrame::OnUpdateButtonsState)
The actual update handler should look like this:
void CMainFrame::OnUpdateButtonsState(CCmdUI* pCmdUI)
{
UINT nVK;
UINT flag = 0x0001;
switch (pCmdUI->m_nID)
{
case ID_INDICATOR_CAPS:
nVK = VK_CAPITAL;
break;
case ID_INDICATOR_NUM:
nVK = VK_NUMLOCK;
break;
case ID_INDICATOR_SCRL:
nVK = VK_SCROLL;
break;
case ID_INDICATOR_KANA:
nVK = VK_KANA;
break;
default:
TRACE(traceAppMsg, 0, "Warning: OnUpdateKeyIndicator - unknown indicator 0x%04X.\n",
pCmdUI->m_nID);
pCmdUI->ContinueRouting();
return; // not for us
}
pCmdUI->SetCheck(::GetKeyState(nVK) & flag);
}
I solved it by moving the code to CChildFrame class.
ON_UPDATE_COMMAND_UI(ID_INDICATOR_CAPS, &CChildFrame::OnUpdateIndicators)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_NUM, &CChildFrame::OnUpdateIndicators)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_SCRL, &CChildFrame::OnUpdateIndicators)
And then
void CChildFrame::OnUpdateIndicators(CCmdUI *pCmdUI)
{
pCmdUI->Enable();
// ... the rest of the above code
CString text;
if (::GetKeyState(nVK) & flag)
text.LoadStringW(pCmdUI->m_nID);
pCmdUI->SetText(text);
}
I have to show the saving message box until timeout.
Once the timeout happens go to slot and do some function.
timerToSave=new QTimer(this);
connect(timerToSave,SIGNAL(timeout()),this,SLOT(SavingStatusSlot()));
Above code is the timer, when timeout moves to the saveslot.
bool PopUpManager::PopUpSaveStaus()
{
timerToSave->start(3000);
saveStatus=false;
if(SetThread::getInstance()->UISaveStatus==ST_PROCESSING)
{
msgBox = new QMessageBox(0);
msgBox->setModal(true);
msgBox->setText("Saving ... ");
msgBox->setIcon(QMessageBox::Information);
msgBox->setStandardButtons(QMessageBox::Ok);
msgBox->setCursor(Qt::WaitCursor);
msgBox->setWindowFlags(Qt::FramelessWindowHint| Qt::WindowStaysOnTopHint);
msgBox->setStyleSheet("background-color:#444;color:#FFF;outline:none;");
msgBox->exec();
}
else
SavingStatusSlot();
return saveStatus;
}
Above method called from other classes, when the user click on the save button.
once the method called, starting the timer then displaying the message box.
if timeout happens calling slot [given below]
void PopUpManager::SavingStatusSlot()
{
msgBox->button(QMessageBox::Ok)->animateClick();
timerToSave->stop();
if(SetThread::getInstance()->UISaveStatus==ST_OK)
{
saveStatus=true;
}
else
{
PopUpWithOKButton(" Saving Error ");
saveStatus=false;
}
}
this code is working, I have used the message box with OK button and when the timeout creating the animated click and doing some function.
Now I want to show the Message box without button and when timeout, close the message box then do some function
But the Message box close() is not working.
void PopUpManager::ClosePopUP()
{
if(msgBox->isEnabled())
msgBox->close();
}
if I call the above code the message box has to close, but it is displaying.
Can anyone help me on this.
Thanks in advance.
I have solved the issue
used msgBox->show(); instead of the msgBox->exec();
and msgBox->hide(); insted of msgBox->close();
code is given below.
bool PopUpManager::PopUpSaveStaus()
{
timerToSave->start(3000);
saveStatus=false;
if(UISaveStatus==ST_PROCESSING)
{
msgBox = new QMessageBox(QMessageBox::Information,"Error","Processing ... ",0,0,Qt::FramelessWindowHint| Qt::WindowStaysOnTopHint);
msgBox->setStandardButtons(0);
msgBox->setCursor(Qt::WaitCursor);
msgBox->setStyleSheet("background-color:#444;color:#FFF;outline:none;");
msgBox->show();
}
else
{
SavingStatusSlot();
}
return saveStatus;
}
void PopUpManager::SavingStatusSlot()
{
msgBox->hide();
timerToSave->stop();
if(UISaveStatus==ST_OK)
{
saveStatus=true;
}
else
{
PopUpWithOKButton(" communication Failed ");
saveStatus=false;
}
}
I have wrote an application in Qt/c++ on OSX. When quitting the app, I'm catching the closeevent to display dialog box
void MainUI::closeEvent (QCloseEvent *event)
{
if( DeviceUnplugged == false) {
ExitDialog = new DialogExit;
ExitDialog->exec();
if(ExitDialog->result() == QDialog::Accepted) {
m_device.CloseDevice();
event->accept();
}
else {
event->ignore();
}
}
}
The dialog box is correctly displayed when closing using the red cross or using the menu "quit".
but when I'm closing the app using the right click on the icon in the dock, the dialog box appears twice the close event is called twice.
Any idea why ?
Yes, I think it is normal for Mac, at least I had this in my Qt application, too (only on Mac).
I used the following workaround:
void MainUI::closeEvent (QCloseEvent *event)
{
if (m_closing)
{
event->accept();
return;
}
if( DeviceUnplugged == false) {
ExitDialog = new DialogExit;
ExitDialog->exec();
if(ExitDialog->result() == QDialog::Accepted) {
m_device.CloseDevice();
m_closing = true;
event->accept();
}
else {
event->ignore();
}
}
}
By default, boolean variable m_closing should be initialized by false of course in your class. This way second time nothing will be done (processing will be skipped). This worked for me.
Looks like this is a QT bug:
See: https://bugreports.qt.io/browse/QTBUG-43344
Also had this problem when using qt-5.6_4 ,
In my case it happened when using CMD+Q but didn't happen when using the red x button.
Used a similar patch.
I avoided accept or ignore since this is a bug and I don't think we should "talk to it" :-)
Instead I simply return when called more then once.
static int numCalled = 0;
if (numCalled++ >= 1)
return;
I am currently dealing with a multi-form application and am having issue registering a del key press, the application that requires the del key is a form with a frame on it with objects painted on it that can be selected, upon pressing the del key the selected objects are to be deleted via a deleteObjects method. The code I am currently using is as follows
void __fastcall TF_Image::KeyUpKbd( WORD &Key )
{
if(Key == VK_DELETE || Key == VK_DKEY)
{
deleteSelectedObjects();
}
}
(Note: There are other paramenters in the function call but they aren't used)
TF_Image inherits from TFrame
I have tried mapping other keys other than the del key ie the D key and have found that the method is called with no problem. I have discovered that when pressing (physically) the del key the methods associated with KeyUp & KeyDown are not called.
Edit: So i've attempted to add the DeleteSelectedOb() method to my WndProc method without much luck either.
void __fastcall TF_ImgBrowserOA::WndProc(TMessage &Message)
{
if (Message.Msg == WM_KEYDOWN)
{
if (Message.WParam == VK_DELETE)
{
F_Image->DeleteSelectedOb();
}
}
//code that manages window resize
TForm::WndProc(Message);
}
The WndProc method doent appear to respond to keystrokes
So after cleaning up some code in some other modules and removing unneccessary menu's I decided to go back and look at this section again after I found a similar piece of code implementing a similar function, I couldn't see much difference between them and so I recompiled and attempted to run my Delete function from the KeyDown event and for some reason it just worked, I suspect it came down to an issue of another element holding focus in the Application. As a precaution I also called a SetFocus() to the frame in which I required this code to operate in. Its still a mystery to me why this didn't work intially though.
Here is a snippet for my TRichEdit control (Script_Edit).
TWndMethod *PrevWndProc = Script_Edit->WindowProc;
Script_Edit->WindowProc = MyWndProc;
void __fastcall My_Form::MyWndProc(TMessage &Message) {
switch (Message.Msg) {
case WM_KEYDOWN: {
// Check for DELETE and BACKSPACE keys
if( Message.WParam == VK_BACK ||
Message.WParam == VK_DELETE
) {
// Do whatever you need
}
break;
default:
// call default handler if not processed
PrevWndProc(Message);
}
}
You can't get much closer to the message core than this with VCL...
I'm developing a project in Qt. I have a QTreeWidget(filesTreeWidget) whith some file names and a button for creating a file. The Create button adds to the filesTreeWidget a new item(the item's text is "") who is edited for choosing a name. When I press ENTER, the filename is send through a socket to the server. The problem comes when I press ESC because the filename remains "" and is not send to the server. I tried to overwrite the keyPressEvent but is not working. Any ideas? I need to catch the ESC press event when I'm editing the item.
You can subclass QTreeWidget, and reimplement QTreeView::keyPressEvent like so:
void MyTreeWidget::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
{
// handle the key press, perhaps giving the item text a default value
event->accept();
}
else
{
QTreeView::keyPressEvent(event); // call the default implementation
}
}
There might be more elegant ways to achieve what you want, but this should be pretty easy. For example, if you really don't want to subclass, you can install an event filter, but I don't like doing that especially for "big" classes with lots of events because it's relatively expensive.
Implement keyPressEvent function as following:
void TestTreeWidget::keyPressEvent(QKeyEvent *event)
{
switch (event->key())
{
case Qt::Key_Escape:
{
escapeKeyPressEventHandler();
event->accept();
break;
}
default:
QTreeWidget::keyPressEvent(event);
}
}
TestTreeWidget::escapeKeyPressEventHandler()
{
// work with your QTreeWidgetItem here
}