How to update modeless dialogbox - c++

I have a modeless dialog box running in a separate thread. I want to update this dialog box from my main program. I tried with creating custom message UPDATE = 0x8001 (in this range WM_APP - 0xBFFF) and associated handler for that message and calling postthreadmessage(). But that is not working. My code look like this.
int _tmain(int argc, _TCHAR* argv[])
{
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), SW_SHOW))
{
std::cout<<"Fatal Error: MFC initialization failed\n";
}
else
{
std::thread th2(ModelessThreadFunc);
DWORD thid = GetThreadId(th2.native_handle());
std::cout<<PostThreadMessage(thid,UPDATE,0,0);
th2.join();
}
return 0;
}
int ModelessThreadFunc()
{
dialog *dial = new dialog;
assert(dial->Create(dialog::IDD));
dial->ShowWindow(SW_SHOWNORMAL);
MSG msg;
while((::GetMessage(&msg, NULL, 0,0) != 0))
{
::peekmessage(&msg,NULL,0x8000,0x8002,0x0001);
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return 0;
}
Can anyone explain problem with above logic? My aim is to update dialog box outside its thread. Any more ideas are welcome. Thank you.

PostThreadMessage is documented to fail if the destination thread creates any windows. You should PostMessage to the dialog HWND. You might also need to use AfxBeginThread instead of std::thread because you need the MFC message pump that is built in to CWinThread.
In general, the approach you are taking is not recommended. All GUI should be in the main thread, and secondary threads used for time-consuming operations. This avoids many awkward problems.

Related

How to befriend QEventLoop and winapi event loop

I have MyApp class with winapi event loop in it
class MyApp : public QObject {
Q_OBJECT
public:
int WINAPI exec() {
MSG msg;
int nRetVal;
while ((nRetVal = ::GetMessage(&msg, nullptr, 0, 0)) != 0 && nRetVal != -1) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return msg.wParam;
}
};
When I start my program, QObject's events won't process (can't invoke any slot and hence send signals).
Somewhere on the internet I found kind of a solution - create a QApplication object, so it somehow "hooks up" to winapi message loop and it worked:
int main(int _argc, char* _argv[]) {
QApplication qa(_argc,_argv);
UNREFERENCED_PARAMETER(qa);
MyApp mapp();
return mapp.exec();
}
But it seems to me that design is fragile and a hack. And I don't like that I'm using some undocumented feature and never call QApplication.exec() method.
Can you tell me how to do it the right way? Namely, I want to call only one exec method (I guess it will be the one of QApplication, but where should I put my winapi loop?)
Thanks for any help

Close a GTK Window

Bear with me as I am very new to GTK and GDK.
I am trying to cycle through several images, make modifications to them (draw a circle at various points), and take user input from stdin.
I wrote C++ classes to wrap around the GTK framework so I can simplify image manipulation. I am currently opening individual windows with each image, asking for input, closing that window and then opening the next.
I can do everything just fine except get the window to close programmatically, and having the user do it isn't acceptable (ie too tedious). Below is the code that opens and closes the window.
void PixelImage::show() {
gtk_widget_show_all(this->window);
gtk_main();
}
void PixelImage::close() {
gtk_window_close((GtkWindow*)this->window);
}
PixelImage::PixelImage(const char *fname) {
this->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(this->window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
this->fname = std::string(fname);
this->image = gtk_image_new_from_file(fname);
this->pix = gtk_image_get_pixbuf((GtkImage*)this->image);
this->pixels = gdk_pixbuf_get_pixels(this->pix);
this->len = gdk_pixbuf_get_byte_length(this->pix);
this->width = gdk_pixbuf_get_width(this->pix);
this->height = gdk_pixbuf_get_height(this->pix);
this->nchannels = gdk_pixbuf_get_n_channels(this->pix);
this->rowstride = gdk_pixbuf_get_rowstride(this->pix);
gtk_container_add(GTK_CONTAINER (this->window), this->image);
}
When close is called after show, the window remains and when I close it, the following error appears.
(img:2173): Gtk-CRITICAL **: gtk_widget_get_realized: assertion 'GTK_IS_WIDGET (widget)' failed
So I am going to answer my own question. Perhaps there is a better way, which I would love to hear, but this is how I solved it.
I used POSIX Threads where I open a thread that opens the image window and then do other things on the main thread. Then I simply called gtk_main_quit() from the main thread. Then I join with the window bearing thread. Here is the code.
static void* gtkStarter(void * a) {
gtk_main();
return NULL;
}
void PixelImage::show() {
gtk_widget_show_all(this->window);
pthread_create(&this->pp, NULL, gtkStarter, NULL);
}
void PixelImage::close() {
gtk_main_quit();
pthread_join(this->pp, NULL);
}
It seems to work pretty well.

MFC App closes on startup

Trying to run a simple MFC App but closes because the program terminates, assuming I need to run the dialog box in a seperate thread but can't work out how.
Here's the code so far:
CWinApp theApp;
using namespace std;
int main(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
theApp.InitApplication();
theApp.InitInstance();
theApp.Run();
AfxWinTerm();
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
MyDialog *mdlg = new MyDialog();
mdlg->Create( IDD_MDLG, theApp.m_pMainWnd);
mdlg->ShowWindow( true );
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
There must be something simple I can do to keep the program from terminating, just not sure how?
Instead of calling:
mdlg->ShowWindow( true );
you should do:
mdlg->DoModal();
Also, I dont think you need Create. If you want to stay with modeless dialog, then you should create message loop before returning from main - something like here http://en.wikipedia.org/wiki/Message_loop_in_Microsoft_Windows
As far as I can see you created a Win32 Console Application and try to add a GUI to it? You should only do that if you really need the console. If not, then better create a new project, select the MFC Application template and choose dialog based application. The wizard will create all you need.
BTW, your
MyDialog *mdlg = new MyDialog();
mdlg->Create( IDD_MDLG, theApp.m_pMainWnd);
mdlg->ShowWindow( true );
should better have been:
MyDialog mdlg;
mdlg.DoModal();
No need for new in your case, so just allocate the object on the stack. And DoModal does what you want.
In my Win32 Console Application with MFC support I was able to show a dialog. But in my wizard generated code these lines were not present, so maybe you should delete them:
theApp.InitApplication();
theApp.InitInstance();
theApp.Run();
AfxWinTerm();

Show dialog before main window

I have a windowed application, which crashes after showing information dialog only before QMainWindow is activated.
Information dialog is shown only if passed data is invalid, however it might be a user interaction (file select / drag) or passed as argument, which causes problems. When / how should I show such error dialog than?
Note: When dialog is only shown (with show() method rather than exec()) it doesn't crash, but dialog gets discarded right away even with setModal( true ).
Any ideas? Thanks,
EDIT:
Some code:
int WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nShowCmd)
{
QApplication app(__argc, __argv);
MBViewer viewer;
viewer.show();
return app.exec();
}
MBViewer::MBViewer()
{
setAcceptDrops(true);
m_ui.setupUi(this);
m_viewer = new Viewer_Widget();
m_ui.preview_layout->addWidget(m_viewer);
parse_parameters();
connect_controls();
connect_actions();
}
void MBViewer::connect_controls()
{
(...)
connect( m_viewer, SIGNAL( view_initialized()), this, SLOT( open_file() ));
(...)
}
void MBViewer::open_file()
{
// somefile is set in parse_parameters or by user interaction
if (!somefile.is_valid()) {
m_viewer->reset();
// This will crash application after user clicked OK button
QMessageBox::information( this, "Error", "Error text", QMessageBox::Ok );
return;
}
(...)
}
Try a message box without pointer to your main window like in this example:
QMessageBox msgBox;
msgBox.setText(text.str().c_str());
msgBox.setIcon(QMessageBox::Question);
QPushButton *speed = msgBox.addButton("Speed optimization", QMessageBox::AcceptRole);
QPushButton *memory = msgBox.addButton("Memory optimization", QMessageBox::AcceptRole);
QPushButton *close = msgBox.addButton("Close", QMessageBox::RejectRole);
msgBox.setDefaultButton(speed);
msgBox.exec();
if (msgBox.clickedButton() == memory)
return true;
if (msgBox.clickedButton() == close)
exit(4);
It works even before creating any window (but after QApplication initialization).
When you call app.exec( ),it starts the main message handler loop which is required to be running before you start displaying dialogs. QMessageBox is a modal dialog when used with exec, so will prevent the app.exec function being called. Therefore, it's likely that messages are being sent before the message handler has been initialised and so a crash is observed.
When show() is used, execution of app.exec is allow to process, which is why the crash doesn't happen.
If you want a modal MessageBox at startup, you'll need to launch it after the message handler has been created / initialised. Not the cleanest way, but you could try launching it on a timer to delay the call to exec.

SFML and GTK+ - GtkFileChooserDialog

I'm writing an app using SFML and I want to use GTK+ to create file chooser dialogs. I have this code:
gtk_init(&argc, &argv);
GtkWidget *dialog;
dialog = gtk_file_chooser_dialog_new ("Open file...", NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
gtk_dialog_run (GTK_DIALOG (dialog));
And the dialog is showing, but it doesn't get destroyed :(
In the gtk_dialog_run documentation there is a note
After gtk_dialog_run() returns, you are responsible for hiding or destroying the dialog if you wish to do so.
So the dialog should not get destroyed automaticaly, the programmer must do it.
EDIT:
The another problem is that you are not running GTK main loop (gtk_main() or its variant) so the GTK can not deal with events necessary to destroy a widget (no part of GTK is running in the time the events are present). The sollution for this is in answer to another question using gtk_idle_add() to invoke function after gtk_main()
is called. In this function the dialog is shown, the result is given to the caller, the dialog is destroyed and gtk_main_quit() is called to terminate GTK main loop.
However, gtk_idle_add() is deprecated in GTK+2.6 and is not present in GTK+3.0, so g_idle_add() should be used instead. Your code could be somethink like
struct fch_result {
gint response;
// other information to return like filename,...
};
static gboolean fch_dialog(gpointer user_data)
{
struct fch_result *result = (struct fch_result *) user_data;
GtkWidget *dialog = gtk_file_chooser_dialog_new ( ... );
result->response = gtk_dialog_run (GTK_DIALOG(dialog));
// now add other information to result
gtk_widget_destroy(dialog);
gtk_main_quit(); // terminate the gtk_main loop called from caller
return FALSE;
}
int main(int argc, char** argv)
{
gtk_init(&argc, &argv);
struct fch_result data;
g_idle_add(fch_dialog, &data);
gtk_main();
// continue with the program
return 0;
}