How to make QDialogButtonBox NOT close its parent QDialog? - c++

I have a QDialog with a QDialogButtonBox widget, and I've connected the button box's accepted signal to a slot in my QDialog subclass, like so:
void MyDialog::on_buttonBox_accepted()
{
QString errorString = this->inputErrorString();
if (errorString.isEmpty())
{
// Do work here
// code code code...
this->accept();
}
else
{
QMessageBox::critical(this, tr("Error"), tr("The following input errors have occurred:") + errorString);
}
}
However, the dialog is closes after the message box is displayed; apparently the button box automatically connects its accepted signal to QDialog's accept slot (I want to call that slot manually). How can I prevent this so I can take the manual approach outlined above?

You can implement MyDialog::accept(). The function is virtual in QDialog.

Related

Qt : catched mouseMoseEvent dont interact with QWebView html page element

I catch the mouseMoveEvent of my QWebView for restarting a timer of a screensaver. The problem is that now the mouseMoveEvent isnt distribued to the HTML elements so its impossible for example to move a sliding bar on the page.
I use connect to bind mouseMoveEvent to the restart slot :
QObject::connect(_view, SIGNAL(mouseMoveEvent(QMouseEvent*)), _mediaPlayer, SLOT(stop()));
WebView class :
class WebView : public QWebView
{
Q_OBJECT
public:
WebView(QString menu) : _menuDesc(menu) {};
WebView(){};
void setMenuDesc(QString menu) {_menuDesc = menu;};
QString getMenuDesc() {return _menuDesc;};
void setCurrPage(QString page) {_currPage = page;};
QString getCurrPage() {return _currPage;};
void setCurrCategory(QString page) {_currPage = page;};
QString getCurrCategory() {return _currPage;};
void mouseMoveEvent(QMouseEvent *)
{
emit mouseMoved();
};
signals :
void mouseMoved();
private:
QString _menuDesc = 0;
QString _currPage;
QString _currCategory = 0;
};
Is there a solution to still catch the signal and pass it to the HTML page?
mouseMoveEvent is not a signal but an event handler. You can reimplement this event handler and let it emit a signal you can connect to if you need that.
Like this:
MyWebView::mouseMoveEvent(QMouseEvent * e) {
emit mouseMoved(); // this would be signal you could connect to.
}
Seems you misunderstand event handler and signal usages.
mouseMoveEvent is a member method of QWidget, is not a signal so you cannot connect to it. You can override it in you subclass and emit your own signal.
And if a QWidget's mouse tracking is switched off, mouse move events only occur if a mouse button is pressed while the mouse is being moved. Maybe you need to call setMouseTracking too.

focusInEvent not called in QLineEdit subclass

I have a Qt/cpp code and display a subclassed QLineEdit. When double-clicking the QLineEdit, the focusInEvent is never called (launched in Maya).
void myQLineEditClass::focusInEvent(QFocusEvent *e)
{
MGlobal::displayInfo(MQtUtil::toMString(QString().sprintf("HERE")));
QLineEdit::focusInEvent(e);
}
HERE is never displayed, event if the focusInEvent is present in the .h protect part. Any idea how to get focusInEvents ?
Try the below. For several occasions that worked for me when focusInEvent did not.
void YourWidget::changeEvent(QEvent* event)
{
if (event->type() == QEvent::ActivationChange)
{
if (isActiveWindow())
{
// gaining the focus
}
else
{
// loosing the focus
}
}
// or whatever *parent* class call is
QWidget::changeEvent(event);
}
The event gets intercepted by the editor widget. See QItemDelegate::createEditor. The widget returned there will get it.
The issue was linked to the fact that the QLineEdit was in a QGraphicsView that was in another QGraphicsView. Bringing the QLineEdit to the higher-level QGraphicsView made it work.

Qt toolbar/qtoolbutton action never triggered

I have the following piece of code, for some reason, from the UI window, MyActionDock inherited from QToolBar, it is displayed without any problem, when clicked on the button, the button color also changed, but the slots (a1ActionSlot(), and a2ActionSlot()) connected to the signals are never called, feel like the action is never triggered. I'm using Qt 4.7.2. What's wrong with it? Thanks a lot.
I believe the code used to work properly for Qt4.6 or earlier. Don't know when the problem happens.
MyActionDock::MyActionDock (QWidget *parent) :
QToolBar (parent)
{
setOrientation (Qt::Vertical);
setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
setFixedWidth(canvas()->toolsDockWidth());
// ACTIONS
QToolButton * a1btn= new QToolButton (this);
a1btn->setText("Action 1");
a1btn->setIcon(QIcon("a1.png"));
a1btn->setToolTip ("Some action a1");
a1btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
QAction *a1Action = addWidget(a1btn);
connect (a1Action , SIGNAL (triggered()), this, SLOT(a1ActionSlot()));
addAction (a1Action);
QToolButton * a2Btn = new QToolButton (this);
a2Btn ->setText("A2");
a2Btn ->setIcon(QIcon("a2.png"));
a2Btn ->setToolTip ("something");
QAction *a2Action= addWidget(a2Btn );
connect (a2Action, SIGNAL (triggered()), this, SLOT(a2ActionSlot()));
addAction (a2Action);
}
void MyActionDock::a1ActionSlot()
{
//do something
}
void MyActionDock::a2ActionSlot()
{
//do something
}
As Jay suggested, directly connect to the QToolButton and don't addAction, then it works. Think this is a Qt upgrade related problem. The code used to work in Qt 4.6 or earlier, but it stopped working after 4.7. So for 4.7 if you want to use QToolButton, direct connect the button's signal.
QToolButton * a2Btn = new QToolButton (this);
a2Btn ->setText("A2");
a2Btn ->setIcon(QIcon("a2.png"));
a2Btn ->setToolTip ("something");
addWidget(a2Btn );
connect (a2Btn , SIGNAL (clicked()), this, SLOT(a2ActionSlot()));
The slot is in the wrong class.
You declare the slot a1ActionSlot is in the class MyActionDock here:
connect (a1Action , SIGNAL (triggered()), this, SLOT(a1ActionSlot()));
The third parameter is 'this' (which points to the MyActionDock class).
You instantiate the a1ActionSlot method in the class QtCanvasActionDock.
void QtCanvasActionDock::a1ActionSlot()

QDialog exec() and getting result value

I have subclassed QDialog to implement functionality similar to QMessageBox ( I needed this to allow for customization). It has a text message and OK, Cancel buttons. I am showing the dialog using exec() to make it blocking. Now, how do I return values of true/false when the user clicks on OK/Cancel?
I tried connecting the buttons to setResult() and then, return the result value when clicked, but
Clicking the buttons does not close the dialog box
the return value is incorrect.
Following is the code I have written. I think I am wrong in the exec/result part - but I am not sure how to fix it.
class MyMessageBox : public QDialog {
Q_OBJECT
private slots:
void onOKButtonClicked() { this->setResult(QDialog::Accepted); }
void onCancelButtonClicked() { this->setResult(QDialog::Rejected); }
public:
MyMessageBox(QMessageBox::Icon icon, const QString& title,
const QString& text, bool showCancelButton = true,
QWidget* parent = 0);
virtual void resizeEvent(QResizeEvent* e);
QDialog::DialogCode showYourself()
{
this->setWindowModality(Qt::ApplicationModal);
this->exec();
return static_cast<QDialog::DialogCode>(this->result());
}
};
The user will instantiate the class and call showYourself() which is expected to return the value and also close(and delete) the dialog.
I have posted partial code. Let me know if you need more and I will post the complete version.
Some points :
Rather than using setResult() yourself, use QDialog::accept() and QDialog::reject().
It seems you are not taking full advantage of the signals and slots. You need the object which create the dialog (or another one) to listen to the signals of the dialog.
In your code you are not connecting signals to slots either.
With my fix onOKButtonClicked and onCancelButtonClicked are unnecessary.
With my fix you don't need showYourself(). Just call exec and with the events
information will flow.
You need to add this code before showing the dialog (this assume it is in a dialog method):
QObject::connect(acceptButton, SIGNAL(clicked()), this, SLOT(accept()));
QObject::connect(rejectButton, SIGNAL(clicked()), this, SLOT(reject()));
In the caller object you have
void someInitFunctionOrConstructor(){
QObject::connect(mydialog, SIGNAL(finished (int)), this, SLOT(dialogIsFinished(int)));
}
void dialogIsFinished(int){ //this is a slot
if(result == QDialog::Accepted){
//do something
return
}
//do another thing
}
Another solution:
// set signal and slot for "Buttons"
connect(YesButton, SIGNAL(clicked()), dlg, SLOT(accept()));
connect(NoButton, SIGNAL(clicked()), dlg, SLOT(reject()));
// show modal window event loop and wait for button clicks
int dialogCode = dlg->exec();
// act on dialog return code
if(dialogCode == QDialog::Accepted) { // YesButton clicked }
if(dialogCode == QDialog::Rejected) { // NoButton clicked }
Case 1 Clicking the buttons does not close the dialog box.
For this you have to close the dialog on respective SLOTS, so Use
void onOKButtonClicked(){ this->setResult(QDialog::Accepted); this->close();}
void onCancelButtonClicked(){ this->setResult(QDialog::Rejected);this->close();}
Note: Only after you have clicked the Ok button or Cancel button in a standard QMessageBox, setResult() function is triggered and the status is changed. It's not the same effect when done vice versa.
Case 2 The return value is incorrect.
I think only after your dialog gets closed, you will have the result available in result() function. So I guess it will be solved, after you have made the changes specified in Case 1.
If it still persists, use your own private member function to resolve it.

Open only one instance of QDialog with show() , and also does the Object is deleted if i close the QDialog

in Qt im opening QDialog windows each time i click some item
im doing it with new , i like to be sure im opening only one instance of QDialog for each item
im clicking :
void foo::treeWidget_itemClicked(QTreeWidgetItem *item,nt column)
.....
QString groupID = item->data(0, Qt::UserRole).toString();
QString groupName = item->text(0);
GroupDialogContainer* pGroupDialogContainer = new GroupDialogContainer(groupID, groupName, this);
pGroupDialogContainer->show();
}
class GroupDialogContainer : public QDialog
{
Q_OBJECT
public:
GroupDialogContainer(QString GroupId,QString GroupName,QWidget *parent=0);
GroupDialogContainer(QWidget *parent=0);
virtual ~GroupDialogContainer();
Ui::GroupDialog ui;
public slots:
void closeEvent(QCloseEvent *event);
};
do i need to keep some kind of hash or vector of GroupDialogContainer ?
also my second question is :
does each time im closing the QDialog window with close () the object pGroupDialogContainer
that was responsible to open it is destroyer ed ? or do i need to delete it when im detecting that the QDIalog has closed?
Yes, you should probably keep some kind of list of your dialogs to keep track of which ones are already open. If your GroupID is your unique ID then you could do something like this:
QMap DialogMap;
void foo::treeWidget_itemClicked(QTreeWidgetItem *item,nt column)
{
.....
QString groupID = item->data(0, Qt::UserRole).toString();
if (! DialogMap.contains(groupID))
{
// Popup the dialog and add it to map
...
DialogMap.insert(groupID, pGroupDialogContainer);
}
}
Now, for the other part. The most important thing is that you need to remove the item from the map when the dialog closes. You could either delete the dialog then, or my suggestion would be to let the dialog delete itself when it closes - as follows:
// set automatic deletion of object on close
setAttribute(Qt::WA_DeleteOnClose);
But as I said, you'll still need to remove the dialog from the Map, or else you'll have a bad pointer in there, and your code will still think the dialog is open.
So you'll need some kind of signal from the dialog to indicate that it is closing. There is the finished(int result) signal, that is called when you trigger a result:
This signal is emitted when the
dialog's result code has been set,
either by the user or by calling
done(), accept(), or reject().
But, you can always create your own signal in your dialog, and emit it when the closeEvent is called in your dialog.
Then in the code that handles the map...
connect( pGroupDialogContainer, SIGNAL(WindowClosed()), this, SLOT(vCleanUpTheMap()));
...
void vCleanUpTheMap()
{
GroupDialogContainer *pDialog = dynamic_cast<GroupDialogContainer *>(sender());
if (pDialog)
{
// Just to keep things clean disconnect from the dialog.
disconnect(pDialog);
// I am assuming that you can get the key groupID from the dialog
// Cause it's a lot easier to remove from a map with the key
DialogMap.remove(pDialog->GetGroupID());
}
}
And that's it.