Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Setting focus to a running QProcess



  • So I am having trouble figuring out a way to bring an application to the forefront for a QProcess. My application is a System Dock that allows users to drag executables from their local PC, and add it to the dock. When adding to the dock, it creates a button with the object name as the directory location of the application added.

    The thread is created in the Widget window like so:
    @
    /*
    // app button clicked (slot)
    */
    void Widget::appButtonClicked()
    {
    // get sender of the signal
    QToolButton *button = qobject_cast<QToolButton *>(sender());

    // format the exe location
    QString temp = button->objectName();
    temp = temp.replace("/", "\\\\");
    temp = "\"" + temp + "\"";
    
    // start the new process
    newProcess = new Process();
    newProcess->exeLocation = temp;
    newProcess->start();
    

    }
    @

    On the button push, I run a QProcess in a thread so that I don't freeze the GUI and allows other processes to be opened as well:
    @
    #include "process.h"

    /*
    // cc
    */
    Process::Process(QObject *parent) :
    QThread(parent)
    {
    exeLocation = "";
    }

    /*
    // class execution loop
    */
    void Process::run()
    {
    // start the proccess
    QProcess process;
    process.start(exeLocation);
    process.waitForFinished(-1);
    }
    @

    What I also am going to do is append the thread to a QList<QThread *> on creation so that I know which process's are active at all times.

    But, I am looking to change the code for button press signal to check if the application has already been opened. As in, I only want one instance of the application running at a time. If it is already running, then I want bring that process to focus / bring the screen to the front.

    Is there any that there is a way to do this in Qt, or is this going to be platform specific? I am currently developing on Windows 7.


  • Moderators

    Bringing the process to the front will be a system-specific thing, I believe.

    Also, there's no need to run your QProcesses in separate threads. You can use "QProcess:startDetached()":/doc/qt-4.8/qprocess.html#startDetached to run the process without blocking, and you can connect to the QProcess's "finished()":/doc/qt-4.8/qprocess.html#finished signal to catch when the process ends.



  • Ah, very nice. Thanks! I have just read this snipet actually that I am going to try to do using the process id:
    http://www.qtcentre.org/threads/42554-QProcess-and-focus-problem

    So I will save my QProcess to a list when created, then to bring it to focus ill have to search the list on click and compare the process id's, then bring it to focus.

    I think it may work :)



  • Gread idea



  • Actually, for some reason, the finished signal is not working with the startDetached() call after I create it on the heap...very odd.

    @
    /*
    // app button clicked (slot)
    */
    void Widget::appButtonClicked()
    {
    // get sender of the signal
    QToolButton *button = qobject_cast<QToolButton *>(sender());

    // format the exe location
    QString temp = button->objectName();
    temp = temp.replace("/", "\\\\");
    temp = "\"" + temp + "\"";
    
    QProcess *exeprocess = new QProcess(this);
    connect(exeprocess, SIGNAL(finished(int)), this, SLOT(processFinished(int)));
    exeprocess->setObjectName(button->objectName());
    exeprocess->startDetached(temp);
    
    // append the process to the list
    processList.append(exeprocess);
    

    }

    /*
    // process finished
    */
    void Widget::processFinished(int state)
    {
    // get sender of the signal
    QProcess *exitprocess = qobject_cast<QProcess *>(sender());

    // loop through the list and match the process id
    for (i=0;i<processList.size();i++){
        if (processList[i]->pid() == exitprocess->pid()){
            // delete the icon
            delete (processList.takeAt(i));
            return;
        }
    }
    

    }
    @



  • That is odd...



  • Found this on another thread:

    QProcess::startDetached() [doc.qt.nokia.com] are static methods and therefore never send signals.



  • So I have somewhat figured it out...and I am kind of stuck but I think I know why. Here's what I did.

    @
    /*
    // app button clicked (slot)
    */
    void Widget::appButtonClicked()
    {
    // get sender of the signal
    QToolButton *button = qobject_cast<QToolButton *>(sender());

    for (i=0;i<processList.size();i++){
        // check if the process is already open
        QStringList objectNameSplit;
        objectNameSplit = QString(processList[i]->objectName()).split("*");
        if (objectNameSplit.size() > 1){
            if (objectNameSplit[0] == button->objectName()){
                Q_PID pidQt = (Q_PID)QString(objectNameSplit[1]).toInt();
                EnumWindows(EnumWindowsProc, (LPARAM)pidQt);  // get the window handles
                return;
            }
        }
    }
    
    // format the exe location
    QString temp = button->objectName();
    temp = temp.replace("/", "\\\\");
    temp = "\"" + temp + "\"";
    
    QString tempWd;
    QStringList tempArgs;
    qint64 tempPid;
    
    // start the process
    QProcess *exeprocess = new QProcess();
    exeprocess->startDetached(temp, tempArgs, tempWd, &tempPid);
    
    // set the object name for future reference
    QString objectName = button->objectName() + "*" + QVariant(tempPid).toString();
    exeprocess->setObjectName(objectName);
    
    // append the process to the list
    processList.append(exeprocess);
    

    }
    @

    When I started the process, I got the process ID. Next if the application is already open, I used the windows API EnumWindows which loops through each window until call false within the callback functions.

    Here is the standard windows api call back function:
    @
    /*
    // window enumeration callback (GLOBAL FUNCTION NOT IN CLASS)
    */
    BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
    {
    // get the window process ID
    DWORD searchedProcessId = (DWORD)lParam;
    DWORD windowProcessId = 0;
    GetWindowThreadProcessId(hWnd,&windowProcessId);

    // check the process id match
    if (windowProcessId == searchedProcessId){
        ShowWindow(hWnd, SW_SHOW);
        return FALSE;
    }
    return TRUE;  //continue enumeration
    

    }
    @

    where I pass in the process ID...If it matches, then I return false and stop the enumeration loop. Unfortunately the ShowWindow function fails to bring the window to the foreground...

    Question, when QProcess starts, does it handle a point to the parent process? or the child process created by the QProcess? Because I might be trying to bring the dock app to the foreground instead of the opened exectuable.


Log in to reply