Created a simple mfc project, then create three dialog and add CDialog class.
TestA, TestB, TestC classes.
In the main frame dialog,
void CMFCApplication3Dlg::OnBnClickedButton1() {
TestA *a = new TestA(CWnd::FromHandle(GetSafeHwnd()));
a->Create(TestA::IDD, CWnd::FromHandle(GetSafeHwnd()));
a->ShowWindow(SW_SHOW);
}
void CMFCApplication3Dlg::OnBnClickedButton2() {
TestB b;
b.DoModal();
AfxMessageBox(L"B closed");
}
Class TestA has,
void TestA::OnBnClickedButton1() {
TestC c;
c.DoModal();
AfxMessageBox(L"C closed");
}
The problem is occur when
Open TestA
Open TestB
Open TestC
Now when i close TestB the AfxMessageBox(L"B closed"); is not run until i close TestC dialog.
Why is this happen?
Related
I googled a lot before writing here. I found a couple of posts but I couldn't quite get them. So I'm starting a new post.
I am developing a simple UI. There is this main class (see below), which is a main dialogue box which is shown when the app is started.
class MainWindow : public QMainWindow
There are few buttons on the MainWindow dialogue box, when I click a button, it hides the MainWindow and opens another QDialog box. This dialogue box is of the class as shown below
class libinsert : public QDialog
I create the libinsert object this way:
void MainWindow::on_pushButton_clicked()
{
this->hide();
libinsert lib; // I create libinsert object this way
lib.setModal(true);
lib.exec();
}
This is libinsert.cpp:
libinsert::libinsert(QWidget *parent) :
QDialog(parent),
ui(new Ui::libinsert)
{
ui->setupUi(this);
}
When the libinsert dialogue box is open, I need to access a socket variable which is a member of class MainWindow. How do I achieve this ?
My main app looks like this:
{
QApplication a(argc, argv);
MainWindow w(sock);
w.show();
return a.exec();
};
Alternatively: in general how are multiple dialogue boxes built, as parent-child relation?
libinsert will not be a child of MainWindow. QDialog-based windows are always top-level windows, regardless of what you pass as their parent when you construct them.
If there will only ever exist a single instance (per process) of MainWindow at any given time, you can give MainWindow a static function which returns a pointer to the window:
class MainWindow : public QMainWindow
{
public:
MainWindow()
{
theWindow = this;
}
virtual ~MainWindow()
{
theWindow = nullptr;
}
static get()
{
return theWindow;
}
static MainWindow *theWindow;
}
MainWindow *MainWindow::theWindow = nullptr;
Your dialogs can then access the main window's members thusly:
MainWindow::get()->someMemberFunction();
A more robust approach is to have libinsert store a pointer to the main window when it is created:
class MainWindow;
class libinsert : public QDialog
{
public:
libinsert(MainWindow *mw)
: mainWindow(mw)
{ ... }
MainWindow *getMainWindow()
{
return mainWindow;
}
MainWindow *mainWindow;
}
When MainWindow creates the dialog, it passes a pointer to itself to the constructor:
void MainWindow::createDialog()
{
libinsert *dialog = new libinsert(this):
}
This approach will work even if there are multiple instances of MainWindow active at the same time.
In my application I have a QDialog which itself contains a complex, QWidget-derived GUI element. The QDialog is modal and opened with exec() and the embedded GUI element handles all user interactions.
So only this child QWidget knows when the QDialog can be closed, which is done this way:
QDialog* parent=qobject_cast<QDialog*>(parentWidget());
if (parent) parent->close();
This is necessary because the QDialog has to be closed and not only the QWidget.
Now a user reported a situation where QDialog::exec() has returned but where the dialog (or only the GUI element?) was still visible. From the log files I can see QDialog::exec() really has returned and the code right after this call was executed.
So my current assumption: the GUI element has lost its parent so that the close() call shown above was not called because "parent" was null.
Any idea how this can happen? Is there a regular way where the parent of a QWidget can disappear?
Generally speaking, using QDialog::exec to reenter the event loop will cause trouble, because suddenly all the code that runs in the main thread must be reentrant. Most likely you're facing fallout from that. Don't reenter the event loop, and you'll be fine or the problem will become reproducible.
If you need to react to the dialog being accepted or rejected, connect code to the relevant slots. I.e. change this:
void do() {
MyDialog dialog{this};
auto rc = dialog.exec();
qDebug() << "dialog returned" << rc;
}
to that:
class Foo : public QWidget {
MyDialog dialog{this};
...
Foo() {
connect(&dialog, &QDialog::done, this, &Foo::dialogDone);
}
void do() {
dialog.show();
}
void dialogDone(int rc) {
qDebug() << "dialog returned" << rc;
}
};
or, if you want to lazily initialize the dialog:
class Foo : public QWidget {
MyDialog * m_dialog = nullptr;
MyDialog * dialog() {
if (! m_dialog) {
m_dialog = new MyDialog{this};
connect(m_dialog, &QDialog::done, this, &Foo::dialogDone);
}
return m_dialog;
}
...
void do() {
dialog()->show();
}
void dialogDone(int rc) {
qDebug() << "dialog returned" << rc;
}
};
It is a horrible antipattern for the child widget to attempt to meddle with the parent. The knowledge that the widget has a parent should not leak into the widget, it should be localized to the parent. Thus, the child widget should emit a signal that indicates that e.g. the data was accepted. When you create the dialog, connect this signal to the dialog's accept() or close() slots:
class MyWidget : public QWidget {
Q_OBJECT
public:
Q_SIGNAL void isDone();
...
};
class MyDialog : public QDialog {
QGridLayout layout{this};
MyWidget widget;
public:
MyDialog() {
layout.addWidget(&widget, 0, 0);
connect(&widget, &MyWidget::isDone, this, &QDialog::accepted);
}
};
I have a Dialog on MFC application.
MyDialog :
{
int variable1;
int variable2;
Class1 cls = new Class1();
}
And in class1()
Class1()
{
void Function1()
void Function2()
}
--
So How to Access and return to variable1 in Class1::Function1()
Class1::Function1()
{
MyDialog dlg = new MyDialog ();
Get x = dlg->variable1; //if like this, variable1 alway=0, because in above line, i'm define new myDialog()
}
I think to delegate on .NET but in MFC application, I can't get it done ?
You can
"extend" your constructor, by adding a pointer to the parent in your child dialog and access your variable or call public functions (requires header of parent)
use SendMessage and handle the messages in your parent dialog
use GetParent in-place and dynamic_cast it to your parent dialog (requires header of parent)
1.
Class1::Class1(MyParent *parent)
{
m_parentPointer = parent;
}
void Class1::Function1(void)
{
m_parentPointer->myPublicVariable;
}
2.
void Class1::Function1(void)
{
CWnd *parent = GetParent();
if (parent)
parent->SendMessage(WM_YOUR_MESSAGE, yourWPARAM, yourLPARAM);
}
//MessageMap of parent
ON_MESSAGE(WM_YOUR_MESSAGE, ParentClassHandler)
LRESULT Parent::ParentClassHandler(WPARAM wp, LPARAM lp)
{
//Process
}
3.
void Class1::Function1(void)
{
CWnd *parent = GetParent();
if (parent)
{
Parent *p = dynamic_cast<Parent*>(parent);
if (p)
{
//Process
}
}
}
If Class1::Function1() needs to access the dialog, then you need a pointer to the dialog in Function1.
void Class1::Function1(MyDialog *dlg) {
}
If you want to store the dialog pointer permanently, then adjust the constructor of Class1.
class Class1 {
public:
Class1(class MyDialog *dlg_) : dlg(dlg_) {}
class MyDialog *dlg;
}
Another, probably better, way to implement it, is to move the code that needs to access Class1 and MyDialog into global functions or into MyDialog member functions. But which way to go depends on what the classes do and which design you want.
You have to start with basic C++ classes before diving in to this. But here is how it's done:
MyDialog dlg = new MyDialog ();
dlg->variable1 = 1; //set the variable
if (IDOK == dlg->DoModal()) //wait for user to click OK
{
int x = dlg->variable1; //get the variable
}
However, dlg->variable1 is not changed unless you drive your own class and do something to change it.
For example, you can use Dialog Data Exchange to assign variable1 to a check box.
void MyDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Check(pDX, IDC_CHECK1, variable1);
}
To try it, use Visual Studio's dialog wizard to create a check box and an edit box. It will probably create check box with resource id IDC_CHECK1, an edit box with resource id set to IDC_EDIT1.
Another option:
use OnInitDialog to assign variable to dialog controls
use OnOK() to get variables from dialog controls:
:
BOOL MyDialog::OnInitDialog()
{
//put `CString m_string1;` in class declaration
BOOL result = CDialog::OnInitDialog();
SetDlgItemText(IDC_EDIT1, m_string1);
return result;
}
void MyDialog::OnOK()
{
GetDlgItemText(IDC_EDIT1, m_string1);
CDialog::OnOK();
}
I'm working on an application that uses a MDI. I have a bunch of toolbox and menu bar defined in a main window containing the QMDIArea.
All subwindows are of the same class. In order to connect the buttons to the active sub window, I did the following think:
void MainWindow::zoomOut() {
QMdiSubWindow* sub_window = central_document_interface->currentSubWindow();
if (sub_window) {
PlanWindow* plan_window = (PlanWindow*)(sub_window->widget());
plan_window->zoomOut();
}
}
I think it would be smarter to reconnect the signals using the subWindowActivated signal. But the problem I have is that I intend to have several types of sub window (different classes). All signal aren't used by all these classes.
I can't manage to find a clean way to differentiate them and connect or not the signals according to their class. How would you do this ?
I created this code for my project:
void MainWindow::slot_menuEditZoomOut() {
WindowAreaManagerInterface::instance()->
LambaOnCurrentCustomWindow<CAbstractZoomAction>([](CAbstractZoomAction *zoom){ zoom->zoomOut(); });
}
Where the WindowAreaManagerInterface is
class WindowAreaManagerInterface : public QMdiArea {
Q_OBJECT
public:
static WindowAreaManagerInterface *instance();
template<class T>
T *currentCustomWindow() {
QWidget *widget = 0;
QMdiSubWindow *subWindow = currentSubWindow();
if (subWindow) widget = subWindow->widget();
return dynamic_cast<T *> (widget);
}
template<class T, typename Func>
void LambaOnCurrentCustomWindow(Func F) {
T *window = currentCustomWindow<T>();
if (window)
F(window);
}
//other methods follow..
}
Hope this help.
I've been searching a lot and I still can't find a good example of how to have multiple windows inside the same application with GTK. My program is in C++ but I don't mind an example in C which would help me understand the principle anyway.
So, the basic idea is to create my own derived object from Gtk::Window as opposed to Gtk::Dialog. Dialog has a run method which works flawlessly to open a modal popup window, but it's not flexible enough for what I'm trying to do. Does anyone know how I'd go about spawning a new window when I click a button in my program?
For example:
void MainWindow::on_button_clicked()
{
NewWindow window;
//Some code to display that window and stay in a loop until told to return
}
Where NewWindow is derived from Gtk::Window as such:
class NewWindow : public Gtk::Window
{
//Normal stuff goes here
}
Anything will help...I'm really confused here!
Another way to have a new window is to create a pointer to a Gtk window variable(Gtk::Window* about_window_;) then set the Gtk window variable to a new instance of the other window (about_window_ = new Window;), after that show the new window (about_window_->show();). Below is a full example of this:
class AboutWindow : public Gtk::Window
{
public:
AboutWindow();
~AboutWindow();
protected:
Gtk::Label lbl_;
};
AboutWindow::AboutWindow()
{
this->set_default_size(100, 100);
this->set_title("About");
lbl_.set_label("About label");
this->add(lbl_);
this->show_all_children();
}
AboutWindow::~AboutWindow()
{
}
class MainWindow : public Gtk::Window
{
public:
MainWindow();
virtual ~MainWindow();
protected:
void onButtonClicked();
void aboutWinClose();
Gtk::Button button_;
Gtk::Label lbl_;
Gtk::Box box_;
Gtk::AboutWindow* aboutw_;
};
MainWindow::MainWindow()
{
this->set_default_size(100, 100);
box_.set_orientation(Gtk::ORIENTATION_VERTICAL);
this->add(box_);
box_.pack_start(lbl_);
lbl_.set_label("a test");
button_.set_label("Open About Window");
box_.pack_end(button_);
button_.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::onButtonClicked));
aboutw_ = 0;
this->show_all_children();
}
MainWindow::~MainWindow()
{
}
void MainWindow::onButtonClicked()
{
if(aboutw_ != 0)
return;
aboutw_ = new AboutWindow;
aboutw_->signal_hide().connect(sigc::mem_fun(*this, &MainWindow::aboutWinClose));
aboutw_->show();
}
void MainWindow::aboutWinClose()
{
aboutw_ = 0;
}
Added for reference.
If you don't want the new window to be modal, then simply create it, show() it, and return from your main window's method without entering a loop.