How do I check if a window/dialog is already open? I used this code to open a new dialog box but everytime I click it the dialog keeps on opening. Obviously not the way settings dialog works.
Class *someClass = new Class();
someclass->show();
In your code you create a new window/widget/dialog everytime.
Initialize *someClass somewhere else and then only show it.
class Foo
{
public:
Foo() { someClass = new SomeClass() }
void fooClicked() { someClass->show() }
private:
SomeClass *someClass;
};
In your calling class (or main application class, or something similar) define a pointer to the class:
dialogclass *someclass;
In the constructor of that main class, initialize the dialog class:
someclass = NULL;
When you want to show the dialog, do something along these lines:
if (!someclass) someclass = new dialogclass(); // Creates a dialog instance if it does not already exist
if (!someclass->isVisible()) someclass->show(); // Only shows the dialog if it is not already shown.
Use QPointer:
QPointer<MyDialog> dialog = new MyDialog(this);
dialog->show();
...
if (dialog) dialog->show();
If dialog exists it will be shown. If it is deleted in the meantime, it will hold 0 instead of an invalid address, and the last line will never be executed - it will not be shown but you can recreate it if needed.
You can make an static pointer on your window class. It allows you to store last opened window object.
class MyWindow : public QWidget {
public :
static MyWindow* instance;
...
}
Whenever you make a new instance you can set instance. When the instance is null you can make a new window. When you want to close the opened window, you should make instance null again. This allows you to have only one open window.
if (MyWindow::instance == NULL) {
MyWindow *w = new MyWindow(...);
MyWindow::instance = w;
}
This design pattern is called Singleton and it allows you to have only one object per a class. Also, this is a bit different because in Singleton, constructor is not public and factory method should be used for making an object but it is similar.
Related
I have created a timer with SetTimer( 1 , 25 , 0 ); during CChildView::PreSubclassWindow().
In CChildView::OnTimer() I do InvalidateRect( 0 , 0 ); to cause an CChildView::OnPaint(). This causes a record from a file to be read and painted.
All of this works just fine.
During MyApp::InitInstance() I created a modeless dialog with several controls that all work as expected.
What I want to do is control the timer running in CChildView from a dialog control.
The problem is, I can't find or have access to the instance of CChildView.
Hence I can't call my SetTimerSpeed() function in CChildView.
How can I do this, please?
When creating the dialog store a pointer to your view in the dialog object. You can just use this one to access the view instance. Add a view-pointer member in your dialog class declaration:
class CMyDialog : public CDialogEx
{
public:
CChildView *pView;
.
.
}
And when calling it:
CMyDialog ctDlg;
ctDlg.pView = this;
ctDlg.DoModal();
// or ctDlg.Create();
The code above of course can be called from a handler (function) in CChildView.
If the application is SDI you don't even need this, you can just store the pointer to the view in a global variable, it is very much OK:
// Declaration in the .h file
extern CChildView *pChldVw;
// Definition in the .cpp file
CChildView *pChldVw;
// CChildView constructor
CChildView::CChildView() noexcept
{
pChldVw = this;
}
If the application is MDI and the dialog is not created in the CChildView code, it is still possible to find the view instance by calling something like:
CMDIFrameWnd *pFrame = (CMDIFrameWnd*)AfxGetApp()->GetMainWnd();
// Get the active MDI child window.
CMDIChildWnd *pChild = (CMDIChildWnd*)pFrame->GetActiveFrame();
// Get the active view attached to the active MDI child window.
CChildView *pView = (CChildView)pChild->GetActiveView();
There are also some "enumeration" functions, like:
GetFirstDocTemplatePosition() / GetNextDocTemplate()
GetFirstDocPosition() / GetNextDoc()
GetFirstViewPosition() / GetNextView()
I'm working on the library, that wraps some MFC classes and methods. I want the user to be able to dynamically create a CDialogEx using a template in memory. For the modal dialogs, I call CDialog::InitModalIndirect and then CDialog::DoModal. For the modeless dialogs, I call CDialog::CreateIndirect and then CWnd::Show.
The code looks something like this:
// inside my library
class MyDialog : public CDialogEx
{
public:
MyDialog(CWnd* parent) : CDialogEx()
{
parent_ = parent;
my_template_data_ = CreateSomeGenericTemplate();
// OnInitDialog should be preferably called here
}
void ShowModal()
{
InitModalIndirect(my_template_data_, parent_);
DoModal(); // but it's called here - too late
}
void ShowModeless()
{
CreateIndirect(my_template_data_, parent_);
Show(); // but it's called here - too late
}
MyButton* GetButton(int id)
{
// returns the instance of my MyButton, which is a subclassed CButton
}
private:
BOOL MyDialog::OnInitDialog() override
{
CDialogEx::OnInitDialog();
// CWnd::Create for the UI controls can only be called here
}
};
// user's code
// user creates the dialog - in the constructor it's not clear if modal or modeless
1. MyDialog user_dialog(some_parent); // here, I need the controls to be created
2. user_dialog.GetButton(42)->SetWindowText(L"new text"); // user wants to initialize his controls
// but he can't, because MyButton::Create was not called yet
3. user_dialog.ShowModal(); // and only then display the dialog
//by default, here the MFC calls OnInitDialog - too late,
//the SetText method needed to be set on line 2.
My problem is, that the dialog's controls (buttons etc.) can only be created inside the CDialog::OnInitDialog method, which is called automatically after DoModal (for modal)/Show (for modeless) methods. I need the controls to be created and properly initialized (with the CWnd::Create method) preferably inside the constructor. I thought about calling Show/DoModal directly inside the constructor but I don't yet know if it's going to be modal or modeless dialog. It there a solution to this? Many thanks in advance.
Why don't you refactor your code and put the common code in a InitUI() method and call it from both sides?
And don't init interface on the constructor. Do it in OnInitDialog for modal; and in Create, or OnCreate (which implies a ON_WM_CREATE() map entry) for modeless dialogs.
I have a simple MainWindow which has a button and an LineEdit. When I type something and click a button, a new Dialog appears with a label that is supposed to display the string I typed.
So basically, I have trouble sending information to another UI.
I tried working with the new class with a string variable, but it didn't work.
I will try to give an example of what I want to do.
//ui2 Dialog
ui2->label->setText(ui->LineEdit->text());
Ui is a an private variable, so it's not accessible from another class.
//mainwindow.cpp
MainWindow::MainWindow(QWidget*){
this->_dialog = new Dialog(this);
//...
}
MainWindow::on_pushButton_clicked(){
_dialog->_labe->setText(ui->lineEdit->text());
}
//dialog.h
class Dialog{
public:
QLabel* _label;
Dialog(QWidget* ){
_label = ui->label;
}
}
I have the following source code:
void Processmethod()
{
QDialog *ProcessMessage = new QDialog;
Ui::DialogProcessMessage *Dialog = new Ui::DialogProcessMessage();
Dialog->setupUi(ProcessMessage); //polymorphy
ProcessMessage->setModal(true);
ProcessMessage->setAttribute(Qt::WA_DeleteOnClose);
connect(Dialog->pushButtonAbort, SIGNAL(clicked()), &Prozess, SLOT(kill()));
connect(&Prozess6, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(helper()));
connect(&Prozess6, SIGNAL(error(QProcess::ProcessError)), this, SLOT(helper()));
connect(this,SIGNAL(enablePushButton(bool)),Dialog->pushButtonClose, SLOT(setEnabled(bool)));
Prozessmeldung->setModal(true);
ProcessMessage->show();
processmethodONE();
}
How can I delete the heap-object Dialog best when the heap-object ProcessMessage is deleted (which is deleted when closed)? Both objects must be created on the heap. Furthermore the class "Ui::DialogProcessMessage" is directly created by the ui-file and therefore any changes in it will be deleted everytime the ui-file is changed.
You need to subclass QDialog, add field in new class for your sub object assign it when creating and add destructor who will free memory of subojbects when your CustomNewSubclassedQDialog if destroyed.
All instances of QObject emit a destroyed(QObject*) signal when they are deleted. Connect ProcessMessage's signal to some other persistent object's slot, and delete your Dialog heap-object from there.
Ref.: Qt documentation for QObject
You can delete the Dialog object in ProcessMessage's destructor.
You'll have to document this to make it clear that ProcessMessage is responsible for the Dialog. Note that this doesn't seem like a good idea. The best approach here is to manually delete both objects when you're done with them. There's nothing restricting anyone from creating a Dialog in automatic storage, which when attempted to be deleted might cause undefined behavior.
Is Ui::DialogProcessMessage a class of your own? Is it derived from QObject? If so, pass the ProcessMessage pointer to the Dialog constructor as its parent. That way ProcessMessage becomes responsible for deleting Dialog. I.e. your declaration of the Ui::DialogProcessMessage class should look something like this:
namespace Ui
{
class DialogProcessMessage: public QDialog
{
Q_OBJECT
public:
DialogProcessMessage(QObject* parent=0) :
QDialog(parent)
{ /* ... */ }
/*
* more stuff ...
*/
};
}
And then, construct Dialog as follows:
Ui::DialogProcessMessage *Dialog = new Ui::DialogProcessMessage(ProcessMessage);
You might want to refer to the Qt documentation for more information.
I have an application that opens a QDialog for some flow, and when it is closed, the QMainWindow is opened.
In the QDialog I create some objects that I'd like to pass as a pointer (or some other way) to the QMainWindow. For example I create a SysTray object that needs to change its state from the QMainWindow. What is the best way? Singletons?
update .
after implementing the sulotion another question was rises , does the QDialog is cleaned from memory that means , invoked its destructor ? i don't think its the case . i have to do some object cleaning , and there destructor never invoked
One approach is to allocate on the heap with the QMainWindow as a parent. The QObject-hierarchy will take care of freeing the memory and you will access the object for the lifetime of the QMainWindow.
If at any point you know for sure that you don't need the QDialog or the shared object anymore, you can call deleteLater.
Example:
class MyDialog : public QDialog
{
Q_OBJECT
QObject* _objToShare;
public:
QObject* objToShare() const { return _objToShare; }
MyDialog(QObject* parent = 0) : QDialog(parent)
{
_objToShare = new QObject(this); // either use this as the parent
// or free by hand in the destructor
}
// ...
};
class MyWindow : public QMainWindow
{
Q_OBJECT
// ...
QObject* ptrToSharedObj; // alternatively you can hold a pointer
// to your MyDialog instance
};
Where you use your QDialog:
MyDialog* d = new MyDialog(this);
d->exec();
ptrToSharedObj = d->objToShare();
// don't delete d explicitly, the QObject hierarchy will take care of that
A better (and likely more memory-friendly) approach is to use a shared pointer implementation. Qt has a variety of smart pointer classes, one of which is QSharedPointer. It is basically a thread-safe, reference-counted pointer which means that if you grab one that points to the shared object of your QDialog, it will not get freed as long as there are any other QSharedPointers pointing to it. Keep in mind that this might cause circular references if you are not careful.
Example:
class MyDialog : public QDialog
{
Q_OBJECT
QSharedPointer<QObject> _objToShare;
// ^ don't delete in the destructor
public:
QSharedPointer<QObject> objToShare() const { return _objToShare; }
MyDialog(QObject* parent = 0) : QDialog(parent)
{
_objToShare = QSharedPointer<QObject>(new QObject);
// no parent to avoid destruction when the dialog is destructed
}
// ...
};
class MyWindow : public QMainWindow
{
Q_OBJECT
// ...
QSharedPointer<QObject> ptrToSharedObj;
};
Where you use your QDialog:
MyDialog d;
d.exec();
ptrToSharedObj = d.objToShare();
From this point on, even if d goes out of scope (i.e. destroyed), you will still have a valid pointer to the shared data (well, of course unless you do something explicitly to invalidate it).
You have a lot of different options. Some of these may not be applicable to your situation:
Case 1: Caller knows best (i.e. procedural programming)
Define a controller that can control the ordering. That control can then act as the intermediary and get the data once the dialog has closed:
void FlowController::displayFlow()
{
MyDialog *dialog = new MyDialog();
YourSharedData *data = NULL;
int result = dialog->exec();
if (result == QDialog::Accepted) {
data = dialog->sharedDataAccessor();
}
MyMainWindow *window = new MyMainWindow();
window->setSharedData(data);
window->exec();
}
Case 2: Message Passing
Create both the dialog and the main window up front. Connect the corresponding signals and slots and let them both be ignorant of one another. This is usually much easier to test and keep decoupled:
void AppLauncher::launch()
{
MyDialog *dialog = new MyDialog();
MyMainWindow *window = new MyMainWindow();
window->connect(
dialog,
SIGNAL(dialogResult(int, const SharedData&)),
SLOT(setDialogResult(int,const SharedData&))
);
}
void MyMainWindow::setDialogResult(int result, const SharedData& sharedData)
{
if (result == Dialog::Accepted) // something domain-specific would be better
{
this->processSharedData(sharedData); // do whatever with it.
}
}
Case 3: Shared State Dependency
Define your shared data up front and make it a dependency for each form. Each form then defines state, acts based on that state, or some combination of both:
void AppLauncher::launch()
{
SharedData *data = this->createSharedData();
MyDialog *dialog = new MyDialog(data);
MyMainWindow *window = new MyMainWindow();
dialog->exec(); // does what it needs with shared data
window->exec(); // checks shared data and acts accordingly
}
Case 4: MVC / MVP / MVVM
You may be able to define your shared state as a model that they both act upon. This may not be much different than case three above.
Case 4: Singleton or global state
It will work, but please don't do it :).
In QDialog you have owner, which is probably QMainWindow. (if not, you may add it there, ore get parent objects until you come to QMainWindow class). You may refer to it when creating new objects...
You can subclass QApplication to have it keep a pointer to your systray object, or other objects which should be available "application wide".
In a Qt application, there is only a single instance of QApplication, available everywhere using the qApp macro.
See this mailing list discussion which also contains an example.