CrossPlatform GUI Programming with wxWidgets [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

CrossPlatform GUI Programming with wxWidgets [Electronic resources] - نسخه متنی

Julian Smart; Kevin Hock; Stefan Csomor

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
توضیحات
افزودن یادداشت جدید











  • Invoking Other Applications


    Sometimes you may want to run other applications from your own application, whether it's an external browser or another of your own applications. wxExecute is a versatile function that can be used to run a program with or without command-line arguments, synchronously or asychronously, optionally collecting output from the launched process, or even redirecting input to and output from the process to enable the current application to interact with it.

    Running an Application


    Here are some simple examples of using wxExecute:


    // Executes asychronously by default (returns immediately)
    wxExecute(wxT("c:\\windows\\notepad.exe"));
    // Does not return until the user has quit Notepad
    wxExecute(wxT("c:\\windows\\notepad.exe c:\\temp\\temp.txt"),
    wxEXEC_SYNC);

    Note that you can optionally enclose parameters and the executable in quotation marks, which is useful if there are spaces in the names.

    Launching Documents


    If you want to run an application to open an associated document, you can use the wxMimeTypesManager class on Windows and Linux. You can find out the file type associated with the extension and then use it to get the required command to pass to wxExecute. For example, to view a249 file:


    wxString url = wxT("c:\\home\\234");
    bool ok = false;
    wxFileType *ft = wxTheMimeTypesManager->
    GetFileTypeFromExtension(wxT("html"));
    if ( ft )
    {
    wxString cmd;
    ok = ft->GetOpenCommand(&cmd,
    wxFileType::MessageParameters(url, wxEmptyString));
    delete ft;
    if (ok)
    {
    ok = (wxExecute(cmd, wxEXEC_ASYNC) != 0);
    }
    }

    Unfortunately, this doesn't work under Mac OS X because OS X uses a completely different way of associating document types with applications. For arbitrary documents, it's better to ask the Finder to open a document, and fo252 files, it's better to use the special Mac OS X function, ICLaunchURL. wxExecute is not always the best solution under Windows either, where ShellExecute may be a more effective function to use fo252 files. Even on Unix, there may be specific fallback scripts you want to use if an associated application is not found, such as .

    To work around these problems, we include the files launch.h and launch.cpp in examples/chap20/launch. This implements the functions wxLaunchFile, wxVi240File, wxViewPDFFile, and wxPlaySoundFile that work on Windows, Linux, and Mac OS X.

    wxLaunchFile is a general-purpose document launcher. Pass a document file name or an executable file name with or without arguments and an optional error message string that can be presented to the user if the operation fails. If a249 file is passed, wxLaunchFile will call wxVi240File. On Mac OS X, it will use the finder to launch a document, and on other platforms, wxMimeTypesManager will be used. Note that on Mac OS X, applications will sometimes be launched such that their window is behind the current application's window. A workaround is to use the osascript command-line tool to bring the window to the front. If the application you have just launched is AcmeApp, you can call


    wxExecute(wxT("osascript -e \"tell application \\\"AcmeApp\\\"\" -e
    \"activate\" -e \"end tell\"));

    For Linux, wxVi240File, wxViewPDFFile, and wxPlaySoundFile include fallbacks for when an associated application is not found. You may want to adjust the fallbacks to your own requirements. wxPlaySoundFile is intended for playing large audio files in a separate application; for small sound effects in your application, use wxSound instead.

    Redirecting Process Input and Output


    There may be times when you want to "capture" another process and allow your application (and/or its user) to control it. This can be preferable to rewriting an entire complex program just to have the functionality integrated in your application. wxExecute can help you integrate another console-based process by letting you redirect its input and output.

    To do this, you pass an instance of a class derived from wxProcess to wxExecute. The instance's OnTerminate function will be called when the process terminates, and the process object can be used to extract output from or send input to the process.

    You can see various examples of wxExecute usage in samples/exec in your wxWidgets distribution. We also provide an example of embedding the GDB debugger in examples/chap20/pipedprocess. We don't provide the toolbar bitmaps or compilable application, but otherwise it's complete and will work on Windows, Linux, and Mac OS X if GDB is available.

    debugger.h and debugger.cpp implement a piped process and a window containing a toolbar and a text control, used for displaying debugger output and getting input from the user to send to the debugger.

    textctrlex.h and textctrlex.cpp implement a control derived from wxStyledTextCtrl but with some wxTextCtrl compatibility functions and standard event handlers for copy, cut, paste, undo, and redo.

    processapp.h and processapp.cpp implement an application class that can handle input from several processes in idle time.

    The debugger is started with


    DebuggerProcess *process = new DebuggerProcess (this);
    m_pid = wxExecute(cmd, wxEXEC_ASYNC, process);

    It can be killed with


    wxKill(m_pid, wxSIGKILL, NULL, wxKILL_CHILDREN);

    To send a command to the debugger, an internal variable is set to let the input to the process to be picked up in idle time:


    // Send a command to the debugger
    bool DebuggerWindow::SendDebugCommand(const wxString& cmd,
    bool needEcho)
    {
    if (m_process && m_process->GetOutputStream())
    {
    wxString c = cmd;
    c += wxT("\n");
    if (needEcho)
    AddLine(cmd);
    // This simple sets m_input to be processed
    // by HasInput in OnIdle time
    m_process->SendInput(c);
    return true;
    }
    return false;
    }

    HasInput is called periodically by the application object from its idle handler and is responsible for sending input to the process and reading output from the standard error and standard output streams:


    bool DebuggerProcess::HasInput()
    {
    bool hasInput = false;
    static wxChar buffer[4096];
    if ( !m_input.IsEmpty() )
    {
    wxTextOutputStream os(*GetOutputStream());
    os.WriteString(m_input);
    m_input.Empty();
    hasInput = true;
    }
    if ( IsErrorAvailable() )
    {
    buffer[GetErrorStream()->Read(buffer, WXSIZEOF(buffer) -
    1).LastRead()] = _T('\0');
    wxString msg(buffer);
    m_debugWindow->ReadDebuggerOutput(msg, true);
    hasInput = true;
    }
    if ( IsInputAvailable() )
    {
    buffer[GetInputStream()->Read(buffer, WXSIZEOF(buffer) -
    1).LastRead()] = _T('\0');
    wxString msg(buffer);
    m_debugWindow->ReadDebuggerOutput(buffer, false);
    hasInput = true;
    }
    return hasInput;
    }

    Note a crucial difference from the code in the wxWidgets exec sample, which assumes that it can read a line at a time. This will cause a hang if a carriage return is not output by the process. The previous code uses a buffer to keep reading as much input as possible, which is safer.

    The ProcessApp class can be used as a base class for your own application class, or you can copy the functions into your class. It maintains a list of processes, registered with the application instance with RegisterProcess and UnregisterProcess, and handles process input in idle time, as follows:


    // Handle any pending input, in idle time
    bool ProcessApp::HandleProcessInput()
    {
    if (!HasProcesses())
    return false;
    bool hasInput = false;
    wxNode* node = m_processes.GetFirst();
    while (node)
    {
    PipedProcess* process = wxDynamicCast(node->GetData(), PipedProcess);
    if (process && process->HasInput())
    hasInput = true;
    node = node->GetNext();
    }
    return hasInput;
    }
    void ProcessApp::OnIdle(wxIdleEvent& event)
    {
    if (HandleProcessInput())
    event.RequestMore();
    event.Skip();
    }


  • / 261