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.
-
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-problemSo 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.