From: crjjrc on 11 Apr 2008 11:28 I think I've got a solution for making a hybrid application that can either be run in GUI or console mode, depending on command-line parameters. However, I've been unable to find an example of such a program using wxWidgets. wx-users contains much discussion about this, but I'm failing to find any code. My solutions follows. If any command-line parameter is passed, no GUI is used. (The check is a bit of a hack on MSW, I know.) Any thing I'm doing wrong? #include <iostream> #include <wx/wx.h> class GUITest : public wxApp { bool OnInit(); }; bool GUITest::OnInit() { wxFrame *frame = new wxFrame(NULL, -1, _T("Test"), wxDefaultPosition, wxDefaultSize); frame->Show(); SetTopWindow(frame); return true; } class GUIlessTest : public wxAppConsole { bool OnInit(); }; bool GUIlessTest::OnInit() { std::cout << "guiless" << std::endl; return false; } #ifdef __WXMSW__ extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, wxCmdLineArgType lpCmdLine, int nCmdShow) { int argc = 2 * lpCmdLine; #else int main(int argc, char **argv) { #endif if (argc == 2) { GUIlessTest *app = new GUIlessTest; } else { GUITest *app = new GUITest; } #ifdef __WXMSW__ return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow); #else return wxEntry(argc, argv); #endif }
From: Vadim Zeitlin on 11 Apr 2008 22:36 On Fri, 11 Apr 2008 08:28:22 -0700 (PDT) crjjrc <crjjrc(a)gmail.com> wrote: c> My solutions follows. If any command-line parameter is passed, no GUI c> is used. (The check is a bit of a hack on MSW, I know.) Any thing c> I'm doing wrong? I don't think you do anything wrong but it would be nicer (e.g. if you intend to put this on the wiki or maybe submit for inclusion in the manual or as a new sample) if wx command line parsing could be used, is it too late to do this in OnCmdLineParsed()? Also, writing GUIlessTest seems rather pointless, usually people want to have their "main()" called if they don't use GUI so you could just replace this class creation with calls to wxInitialize (or use wxInitializer) and call some console_main() function. Regards, VZ -- TT-Solutions: wxWidgets consultancy and technical support http://www.tt-solutions.com/
From: crjjrc on 14 Apr 2008 10:04 On Apr 11, 9:36 pm, Vadim Zeitlin <va...(a)wxwidgets.org> wrote: > On Fri, 11 Apr 2008 08:28:22 -0700 (PDT) crjjrc <crj...(a)gmail.com> wrote: > > c> My solutions follows. If any command-line parameter is passed, no GUI > c> is used. (The check is a bit of a hack on MSW, I know.) Any thing > c> I'm doing wrong? > > I don't think you do anything wrong but it would be nicer (e.g. if you > intend to put this on the wiki or maybe submit for inclusion in the manual > or as a new sample) if wx command line parsing could be used, is it too > late to do this in OnCmdLineParsed()? Considering that OnCmdLineParsed() is a member of wxAppConsole, I don't think this could be done since we are using the command-line arguments to figure which application to create. Or am I missing something? Alternately I can just trigger the parsing myself by instancing a wxCmdLineParser in main() or WinMain() and calling Parse(), right? I'm not sure how to get the appropriate argc and argv for the parser's constructor though. On Windows, I get one string in lpCmdLine, which doesn't include the program name. Does wxCmdLineParser::SetCmdLine() expect the program name to be first? It doesn't say in the docs. Everywhere else, the incoming argv is char ** and the constructor expects wxChar **. Is there an easy way to convert this? wxApp* objects set their own argc and argv somewhere behind the scenes, and I'm not sure how they do it. - Chris
From: crjjrc on 15 Apr 2008 10:56 On Apr 14, 2:53 pm, Vadim Zeitlin <va...(a)wxwidgets.org> wrote: > c> Considering that OnCmdLineParsed() is a member of wxAppConsole, I > c> don't think this could be done since we are using the command-line > c> arguments to figure which application to create. Or am I missing > c> something? > > I thought about deriving a wxGUIOrConsoleApp class from wxApp (i.e. the > GUI version) but overriding its virtual Initialize() to call wxAppConsole > version if argc != 1. I didn't test it but I think it should be possible to > make this work. I like this idea quite a bit. I found I had a bit more to do to get it to work, and more things probably remain. I had to override wxApp::CleanUp() since it too fiddled with GTK. And I had to make sure the active log target was stderr instead of wxLogGui. It seemed the most correct way to do this was derive a new wxAppTraits class and override CreateLogTarget(). Here's the code, which now uses wxCmdLineParser: ------------ #include <iostream> #include <wx/wx.h> #include <wx/apptrait.h> #include <wx/cmdline.h> class HybridTraits : public wxGUIAppTraits { public: HybridTraits(bool gui_enabled) : wxGUIAppTraits(), gui_enabled(gui_enabled) { } wxLog *CreateLogTarget() { if (gui_enabled) { return wxGUIAppTraits::CreateLogTarget(); } else { return new wxLogStderr; } } private: bool gui_enabled; }; class GUITest : public wxApp { private: bool OnInit(); bool Initialize(int& argc, wxChar **argv) { static const wxCmdLineEntryDesc desc[] = { { wxCMD_LINE_SWITCH, "c", "console", "run in console mode" }, { wxCMD_LINE_NONE } }; wxCmdLineParser parser(desc, argc, argv); if (parser.Parse(true) != 0) { exit(1); } gui_enabled = !parser.Found("c"); if (gui_enabled) { return wxApp::Initialize(argc, argv); } else { return wxAppConsole::Initialize(argc, argv); } } void CleanUp() { if (gui_enabled) { wxApp::CleanUp(); } else { wxAppConsole::CleanUp(); } } HybridTraits *CreateTraits() { return new HybridTraits(gui_enabled); } bool gui_enabled; }; bool GUITest::OnInit() { wxString msg; if (gui_enabled) { msg = "in gui mode"; } else { msg = "in console mode"; } wxLogMessage(msg); return false; } IMPLEMENT_APP(GUITest); ------------ Vadim, if you think this would make a good sample, I'm happy to make any changes to get it to a presentable state. > You can use wxCmdLineParser::ConvertStringToArgs() just as the code in > src/msw/main.cpp does. But, again, hopefully this is unnecessary anyhow. Good to know. Thanks! - Chris
From: crjjrc on 16 Apr 2008 11:32 On Apr 15, 12:39 pm, Vadim Zeitlin <va...(a)wxwidgets.org> wrote: > c> I like this idea quite a bit. I found I had a bit more to do to get > c> it to work, and more things probably remain. I had to override > c> wxApp::CleanUp() since it too fiddled with GTK. > > Sorry, what exactly was the problem? I think we should fix it in wxGTK. Well, the assertion failure occurs in wxApp::CleanUp in src/gtk/ app.cpp. At last checkout, this was line 529. void wxApp::CleanUp() { if (m_idleSourceId != 0) g_source_remove(m_idleSourceId); // release reference acquired by Initialize() g_type_class_unref(g_type_class_peek(GTK_TYPE_WIDGET)); // line 529 However, I don't think we can say it constitutes a bug. If I override Initialize(), in which the GTK libraries are dynamically loaded and which fails if they're not, I should probably expect that I need to override any other wxApp functions that assume GTK is available. > Yes, I think this is a useful example and I'd be favourable to adding it > as a new sample. I don't have a good name for it though ("hybrid" is too > generic), do you? guioptional? guinogui? I'm not sure how to address any Windows issues, since I don't have a Windows machine to build on. It was my understanding that wApps do not show the console window at all, which would be the case here. wxAppConsoles, on the other, optionally show the console window. - Chris
|
Pages: 1 Prev: Failed to build wxGTK on Ubuntu 7.10 Next: using wxScrolledWindow with wxSimpleHtmlListBox |