I am putting a QMesssageBox inline with the shortcutkey of CTRL + N (it means new file will be open). When I press and hold the shortcut key when the object is animating. Is it UI problem of Linux since I am using Linux OS and then I try in other OS and it is not happening, or any codes that I forgot?
Thank you.
If your goal is to have at most one QMessageBox appear at a time, you can ensure that in your code via something like this:
static QMessageBox * openMBox = NULL;
void MyClass :: showMessageBox()
{
if (openMBox) return; // don't open a new QMessageBox if we already have one open!
openMBox = new QMessageBox(args here...);
connect(openMBox, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(userClickedButton(QAbstractButton*)));
openMBox->show();
}
void MyClass :: userClickedButton(QAbstractButton * button)
{
if (openMBox)
{
// [code to handle button-click result could go here]
openMBox->deleteLater();
openMBox = NULL;
}
}
Note that showMessageBox() will only actually create a new QMessageBox if openMBox is NULL, which is to say, only if there isn't already a message-box present.
(The code calls deleteLater() in the userClickedButton() method instead of using the delete operator because it's likely that the userClickedButton() method is itself being called from within a method of the QMessageBox object, therefore we don't want to delete the QMessageBox object until later when it's not in the middle of a method-call)
Related
I am using wxAutomationObject to export data to MS Excel. I have created a few helper classes ExcelApp, ExcelWorkbook etc... all of which inherits from wxAutomationObject.
Briefly, ExcelApp is as follows:
class ExcelApp :public wxAutomationObject
{
public:
ExcelApp(WXIDISPATCH* dispatchPtr = NULL);
~ExcelApp() = default;
void Quit();
std::unique_ptr<ExcelWorkbook> CreateWorkbook(bool Visible = true);
std::vector<std::unique_ptr<ExcelWorkbook>> GetOpenedWorkbooks();
long GetNumberofOpenedWorkbooks() const;
private:
wxAutomationObject m_App;
};
The constructor is implemented as follows:
ExcelApp::ExcelApp(WXIDISPATCH* dispatchPtr):wxAutomationObject(dispatchPtr)
{
if (!m_App.GetInstance("Excel.Application"))
throw std::exception("An instance of Excel object could not be created.");
}
And to create a workbook, I used to following code:
std::unique_ptr<ExcelWorkbook> ExcelApp::CreateWorkbook(bool Visible)
{
auto wb = std::make_unique<ExcelWorkbook>();
bool suc = m_App.GetObject(*wb, "Workbooks.Add");
if (!suc)
return nullptr;
if (Visible)
m_App.PutProperty("Visible", true);
return std::move(wb);
}
This whole OLE implementation is part of a dynamic menu. Part of the code for the event handler for menu is:
void MyFrame::OnExportToExcelButtonHandler(wxCommandEvent& event)
{
auto item = static_cast<wxMenu*>(event.GetEventObject());
std::unique_ptr<ExcelWorkbook> xlsWB ((ExcelWorkbook*)event.GetEventUserData());
bool CreateNewWB = false;
try
{
//Export either the entire workbook or the active worksheet to a new Workbook
if (xlsWB == nullptr)
{
auto xlsApp = ExcelApp();
xlsWB = std::move(xlsApp.CreateWorkbook());
CreateNewWB = true;
}
In terms of exporting data and formatting, everything works fine. However, after closing the created Workbooks Excel.exe still remains in the taskbar list. I wonder what I could be missing?
By the way, I tried the very basic sample shipped with wxWidgets and there seems to remain no ghost instances of Excel after quitting. I
I am using wxWidgets 3.1.4 on Windows 10 using VS 2019.
EDIT 1:
The ribbon button that generates the dynamic menu:
void MyFrame::OnExportToExcelButtonClicked(wxRibbonButtonBarEvent& event)
{
auto excel = sys::win32::ole::ExcelApp();
auto PrepareMenu = [&](wxMenu* Menu)
{
try
{
wxMenuItem* item1 = Menu->Append(wxID_ANY, "New Excel Workbook");
item1->SetBitmap(wxArtProvider::GetBitmap(wxART_NEW));
Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnExportToExcelButtonHandler, this, item1->GetId());
auto wbs = excel.GetOpenedWorkbooks();
if (wbs.size() > 0)
{
for (int i = 0; i < wbs.size(); ++i)
{
auto ExcelWB = std::move(wbs[i]);
wxMenuItem* item1 = Menu->Append(wxID_ANY, ExcelWB->GetFullName());
Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnExportToExcelButtonHandler, this, item1->GetId(), wxID_ANY, ExcelWB.release());
}
}
}
}
The problem seems to originate from the following line:
Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnExportToExcelButtonHandler, this, item1->GetId(), wxID_ANY, ExcelWB.release());
The ExcelWB pointer is now owned by the wxWidgets system and therefore a reference remains and thus the ghost Excel.exe remains.
To solve it, in the following procedure I added:
void MyFrame::OnExportToExcelButtonHandler(wxCommandEvent& event)
{
Unbind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnExportToExcelButtonHandler, this, event.GetId(), wxID_ANY, xlsWB.get());
But the problem still remains. I am not sure how to properly get rid of the pointer that is now owned by the menu. I redesigned some parts with shared_ptr and it did not help.
You already may be doing that but just to be sure.
When debugging such things, make sure the application instance is always visible so you can see when it for example gets stuck waiting on a user input, e.g., asking to save a modified workbook, preventing it from quitting.
I have written wxWidgets-based MS Excel automation wrapper wxAutoExcel (it uses a shared instead of unique pointer for Excel objects) and I have never encountered application ghosts, except when I terminated my application when debugging, without disposing Excel objects.
BTW, I do not get why your ExcelApp both derives from wxAutomationObject and has wxAutomationObject as a member variable (m_App). What is the IDispatch used in the ExcelApp ctor for?
Finally, it seems like I solved the issue, using the following steps:
Instead of a menu, now a dialog is used; therefore, the menu does not own the pointer anymore.
All wxAutomationObject inheriting objects are passed around via std::unique_ptr.
I am building a gtkmm application. The program open with a setting window asking the user to specify some information, and when sanity checks are done, this window should be closed, and the maih window of the application should open.
Right now, opening the main window, and hiding the setting window completely close the application.
From the setting windows, I am doing:
MainWindow* main_window = new MainWindow();
main_window->show();
this->hide();
How can I get the behavior described above ?
Apparently, you can add and remove windows from a Gtk::App. Would it does what I described, and does it mean I would have to pass to my window the Gtk::App pointer ? Thanks.
What seems to be the proper solution is to pass to the window the application pointer (m_app), add the new window to it, show that window and hide the current one. Removing the current one from the application will let the run() function return:
MainWindow* main_window = new MainWindow(m_app);
m_app->add_window(*main_window);
main_window->show();
this->hide();
m_app->remove_window(*this);
delete->this;
This work, but this might not be the proper way of doing things.
Although the question is quite old, I will show my approach which may help someone else to deal with this task.
I use a general application object which holds all window objects: MainApplication.cpp
MainApplication::MainApplication(int argc, char **argv)
{
// Creating the main application object as first
mainApp = Gtk::Application::create(argc, argv, APPLICATION_ID);
// Create the entry window
createEntryWindow();
}
int MainApplication::run()
{
if (!isRunning) {
// Set the current window to entry window for startup
currentWindow = entryWindow;
return mainApp->run(*entryWindow);
} else {
return -1;
}
}
void MainApplication::createEntryWindow()
{
// Load the entry_window.glade layout with the Gtk::Builder Api
Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file("../layout/entry_window.glade");
// Calls the constructor of my own derived widget class which details are specified inside the builder file
builder->get_widget_derived(WND_ENTRY, entryWindow);
// Set this main application object to the new window
entryWindow->setMainApplicationContext(this);
}
MainApplication.h
static const int WS_ENTRY = 100;
static const int WS_SOMETHING = 200;
class MainApplication {
public:
MainApplication(int argc, char* argv[]);
int run();
void switchCurrentWindow(int specifier);
private:
void createEntryWindow();
private:
Glib::RefPtr<Gtk::Application> mainApp;
Gtk::Window* currentWindow = nullptr;
EntryWindow* entryWindow = nullptr;
bool isRunning = false;
};
The MainApplication object will be created inside the main() and after that run() is called: main.cpp
int main(int argc, char* argv[])
{
// Create main application object
MainApplication mainApplication(argc, argv);
// Starts the event loop
// No events propagate until this has been called
return mainApplication.run();
}
The EntryWindow.cpp looks like this (just a simple example):
EntryWindow::EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade)
: Gtk::Window(object), builder(refGlade)
{
// Set widgets to builder
builder->get_widget(btnName, btn);
// Set on click methods for signal_clicked
btn->signal_clicked().connect(sigc::mem_fun(*this, &EntryWindow::onBtnClicked));
}
void EntryWindow::onBtnClicked()
{
mainApplicationContext->switchCurrentWindow(WS_SOMETHING);
}
void EntryWindow::setMainApplicationContext(MainApplication* mainApplication)
{
this->mainApplicationContext = mainApplication;
}
EntryWindow.h:
class EntryWindow : public Gtk::Window {
public:
EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade);
void setMainApplicationContext(MainApplication* mainApplication);
protected:
void onBtnClicked();
protected:
const Glib::RefPtr<Gtk::Builder> builder;
Gtk::Button* btn;
private:
MainApplication* mainApplicationContext = nullptr;
const Glib::ustring btnName = BTN_NAME;
};
So now when the button was clicked, you can switch the windows with following function inside the MainApplication class:
void MainApplication::switchCurrentWindow(int specifier)
{
// Check if the passed specifier exist
int tmpSpecifier = 0;
switch (specifier) {
case WS_ENTRY:
tmpSpecifier = WS_ENTRY;
break;
case WS_SOMETHING:
tmpSpecifier = WS_SOMETHING;
break;
default:
tmpSpecifier = 0;
}
// If the specifier exist
if (tmpSpecifier != 0) {
// Increase the use counter of the main application object
mainApp->hold();
// Hide the current window
currentWindow->hide();
// Remove the current window
mainApp->remove_window(*currentWindow);
} else {
return;
}
switch (tmpSpecifier) {
case WS_ENTRY:
currentWindow = entryWindow;
break;
case WS_SOMETHING:
currentWindow = somethingWindow;
break;
}
// Add the new current window
mainApp->add_window(*currentWindow);
// Show the new window
currentWindow->show();
// Decrease the use counter of the main application object
mainApp->release();
}
Summary: Create an Object which holds all windows. So whenever you need to have a new window, you have to create it inside this object. This main application object will be called by the main() and there it will call run() when the application is ready to start. After that you will handle which window is shown and hidden by the main application object only.
In response to your answer: delete->this is a pure syntax error, and even without ->, writing delete this is usually a code smell. Barring that, what you did seems like it will work, if perhaps not be as intuitive as it could be.
However, doing things in that sequence is not always possible. For example, you may not know what the next Window will be. Perhaps which window opens next depends on an HTTP response that may take a while to arrive.
The general solution is to call Application.hold() before removing the Window. Calling .hold() increments the use count of the GApplication, just as adding a window does. The app quits when its use count is zero. Saying its life is controlled by windows is just a quick way to approximate an explanation of that (and is obviously only relevant to GtkApplication, not the base GApplication). Removing a window decrements the use count.
So, in this case, you would now go from a use count of 2 to 1 - not 1 to 0 - so removing the 1st window would no longer make the app quit. Then, after you add the 2nd window, however much later that occurs, call .release() to remove the extra use count, so the remaining window(s) now exclusively control the application's lifetime again.
I'm trying to update a label value from a background thread. I understand that there are several example, but I'm still having trouble understanding why the below code throw an stack overflow error. It seems like every time setTitle() is executed it goes through the true part of the if statement.
Set title Function:
void setTitle(char data[])
{
String^ temp = gcnew String(data);
if(this->lastSeen1->InvokeRequired)
{
setTitleDelegate^ d = gcnew setTitleDelegate(this, &setTitle);
d->Invoke(data);
}else
{
this->lastSeen1->Text = temp;
this->lastSeen1->Visible = true;
}
}
delegate:
delegate void setTitleDelegate(char data[]);
Thank you
Well, because of this:
d->Invoke(data);
See, here you're calling Delegate::Invoke, which basically means that setTitle just calls itself immediately. You need to call Control::Invoke instead, so you need to call it on an instance of Control, something like this:
this->lastSeen1->Invoke(d, /* any args here */);
I don't know why you're passing a char[] here, it's better not to mix native and managed data structures too much, if you can then just use String^ instead (but even then, C++/CLI isn't really meant for UI development either...).
I think I must be "doing something wrong" here. I have a program using gtkmm. The main window for the program is a subclass of Gtk::Window and I have the bare bones of the application drawn out in Glade.
Here's an edited version of the main window's constructor:
template<class T>
static T*
get_widget (Glib::RefPtr<Gtk::Builder> builder, const Glib::ustring& name)
{
T* widget;
builder->get_widget (name, widget);
if (! widget) no_such_widget (name);
return widget;
}
app_window::app_window ()
{
Glib::RefPtr<Gtk::Builder> builder;
try {
builder = Gtk::Builder::create_from_file (installed_ui_name);
}
catch (const Glib::FileError& err) {
g_error ("Couldn't open UI definition file at %s",
installed_ui_name);
throw;
}
// main_box is a std::unique_ptr<Gtk::Widget>, a field of app_window.
//
// This works fine: the Gtk::Box gets added as the main child of this
// app_window and survives until the app_window is destroyed.
main_box.reset (get_widget <Gtk::Box> (builder, "main-box"));
add (* main_box);
auto accel_group = get_accel_group ();
// This doesn't work so well
//
// menu_quit is a Gtk::MenuItem*. The object seems to be actually
// constructed for the call to builder->get_widget, because its existence
// stops the menu item from being finalized at the end of the application.
auto menu_quit (get_widget<Gtk::MenuItem> (builder, "menu-quit"));
menu_quit->add_accelerator ("activate", accel_group,
GDK_KEY_q, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
using std::bind;
menu_quit->signal_activate ().connect (bind (& app_window::on_close, this));
show ();
}
When setting up the window, I want to register various signal handlers for menu items etc. (the menu_quit widget in the example is just one of them). To do so, I think I need to use builder->get_widget() to get hold of an object to talk about.
The problem is that I've now got an instance of (a subclass of) Gtk::Widget and I don't know what to do with it. If I call delete on the pointer, the widget doesn't appear in the application, but no other problems happen. That's a bit confusing: I would expect either no effect or a segmentation fault (depending on whether something else thought it owned the object or not).
If, on the other hand, I leak the pointer, assuming that object will be owned by the container into which main_box has been added, I get a memory leak. In particular, menu_quit's underlying gtk_image_menu_item doesn't get finalised because the reference count is one too high. (I can check easily enough that with GDB)
A "solution" is to store a pointer to each object that I get with builder->get_widget as a field in the app_window and then delete it in the destructor (automated with std::auto_ptr or std::unique_ptr). But that's really horrible: I don't want to have to write out a field for every single menu item! Avoiding that sort of nonsense was the whole point of using GtkBuilder in the first place!
Assuming that this isn't a bug (gtkmm 3.12.0, if that's relevant), I assume I'm just doing it wrong. How is an application supposed to do this?
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.