PDA

View Full Version : Key presses get lost after starting external process via QProcess in QWidget



donelron
18th June 2021, 10:33
Dear all,

to show my problem I have a minimal working example with a mainwindow that basically consists of
1) a label on the left that receives key presses
2) a widget on the right side that opens SumatraPDF.exe (I am on Windows10) via QProcess and displays a PDF
3) a status bar that displays the number of key presses received on the label and the current focus widget of the QApplication
In order to run the MWE you need to have SumatraPDF.exe in the QCoreApplication::applicationDirPath()
Before SumatraPDF has started the label on the left receives all key presses. After it is started I am facing the problem, that the label on the left does not receive key presses any more even if it is the current focus widget. I have added the info to the status bar (as indicated in 3) above) because using breakpoints instead would make it virtually impossible to debug it in any meaningful way.
Mouse presses do not seem to be affected at all.

I am using Qt5.15 and QtCreator 4.13.2

The problem disappears if I switch to Qt4.8!



# My .pro file
QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

SOURCES += main.cpp \
cpp.cpp

HEADERS += h.h


# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target




My main.cpp
#include "h.h"

#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}






// My h.h
//#ifndef MAINWINDOW_H
//#define MAINWINDOW_H

#include <QMainWindow>


class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void setupUi();
QString updateMessage();

signals:
void updateStatusBar(const QString&, int );

private slots:
//void change

void applicationFocusChanged(QWidget* old, QWidget* current);
void keyPressOnLabel(int updateCount);


private:
int labelKeypressCount;
};
//#endif // MAINWINDOW_H


//#ifndef EXTERNALAPPLICATIONWIDGET_H
//#define EXTERNALAPPLICATIONWIDGET_H

#include <QWidget>
#include <QProcess>

class QLabel;

class ExternalApplicationWidget : public QWidget
{
Q_OBJECT
public:
explicit ExternalApplicationWidget(QWidget *parent = nullptr);
void loadUrl( const QString &fileName);

private:
void startProcess(const QString & program, const QStringList & arguments);

private slots:
void openPDF();

private:
QLabel* filepathLabel;
QWidget *pdfWidget;
QProcess* p;
HWND hwnd;

signals:

};

//#endif // EXTERNALAPPLICATIONWIDGET_H

//#ifndef MYCUSTOMLABEL_H
//#define MYCUSTOMLABEL_H

#include <QLabel>
//#include <QDesignerCustomWidgetInterface>
//#include <QtUiPlugin/QDesignerCustomWidgetInterface>

class MyCustomLabel : public QLabel
{
Q_OBJECT
public:
explicit MyCustomLabel(QWidget *parent = nullptr);

signals:
//void keyPressed(const QString&, int timeout = 0);
void keyPressed(int count);

protected:
void mousePressEvent(QMouseEvent *ev) override;
void keyPressEvent(QKeyEvent *ev) override;

private:
int countKeypresses;

};

//#endif // MYCUSTOMLABEL_H





// My cpp.cpp
#include "h.h"

#include <QApplication>
#include <QFileInfo>
#include <QMessageBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QFileDialog>



ExternalApplicationWidget::ExternalApplicationWidg et(QWidget *parent) : QWidget(parent)
{
QVBoxLayout* vbox = new QVBoxLayout(this);

QWidget* selectPDFWidget = new QWidget(this);
selectPDFWidget->setObjectName("selectPDFWidget");
QHBoxLayout* hbox = new QHBoxLayout(selectPDFWidget);
filepathLabel = new QLabel(this);
filepathLabel->setObjectName("filepathLabel");
hbox->addWidget(filepathLabel);
QPushButton* button = new QPushButton("Select PDF", this);
button->setObjectName("button");
hbox->addWidget(button);
connect(button, SIGNAL(clicked()), this, SLOT(openPDF()));

pdfWidget = new QWidget(this);
pdfWidget->setAutoFillBackground( false );
pdfWidget->setAttribute(Qt::WA_NoSystemBackground, true);
pdfWidget->setAttribute(Qt::WA_OpaquePaintEvent, true);
pdfWidget->setObjectName("pdfWidget");
vbox->addWidget(selectPDFWidget, 1);
vbox->addWidget(pdfWidget, 5);
}


void ExternalApplicationWidget::loadUrl( const QString &fileName)
{
if( !QFileInfo(fileName).exists() ) {
return;
}

QString pth = qApp->applicationDirPath() + "/SumatraPDF.exe";
if( !QFile::exists(pth) ) {
QMessageBox::critical(this, "Red alert!",tr("SumatraPDF.exe could not be loaded!"),tr("&Ok"));
return;
}
QString pdf_filepath = QFileInfo(fileName).absoluteFilePath();
filepathLabel->setText(pdf_filepath);

QStringList args;
args << "-zoom" << "fit page";
args << pdf_filepath;
args << "-plugin" << QString::number((qulonglong)pdfWidget->winId());
startProcess("SumatraPDF.exe",args);
}

void ExternalApplicationWidget::startProcess(const QString &program, const QStringList &arguments)
{
p = new QProcess(this); //OK
p->start(program, arguments); // steals "focus" !!!
p->waitForStarted();
}

void ExternalApplicationWidget::openPDF()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open PDF"), "C:/temp", tr("PDF Files (*.pdf)"));
if( fileName.isEmpty() ) {
return;
}
loadUrl(fileName);
}


#include <QHBoxLayout>
#include <QMenuBar>
#include <QStatusBar>
#include <QApplication>


MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
,labelKeypressCount(0)
{
setupUi();
}

MainWindow::~MainWindow()
{
}


void MainWindow::setupUi()
{
int width = 1400;
int height = 1500;
QWidget* centralwidget = new QWidget(this);
centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
QWidget* horizontalLayoutWidget = new QWidget(centralwidget);
horizontalLayoutWidget->setObjectName(QString::fromUtf8("horizontalLayoutWidget"));
horizontalLayoutWidget->setGeometry(QRect(59, 29, width, height));
QHBoxLayout* horizontalLayout = new QHBoxLayout(horizontalLayoutWidget);
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
horizontalLayout->setContentsMargins(0, 0, 0, 0);
MyCustomLabel* labelWidget = new MyCustomLabel(horizontalLayoutWidget);
labelWidget->setObjectName(QString::fromUtf8("MyCustomLabel"));
labelWidget->setText("The status bar counts key presses on this label!");

horizontalLayout->addWidget(labelWidget);

ExternalApplicationWidget* externalApplicationWidget= new ExternalApplicationWidget(horizontalLayoutWidget);
externalApplicationWidget->setObjectName(QString::fromUtf8("ExternalApplicationWidget"));

horizontalLayout->addWidget(externalApplicationWidget);
setCentralWidget(centralwidget);
QStatusBar* statusbar = new QStatusBar(this);
statusbar->setObjectName(QString::fromUtf8("statusbar"));
setStatusBar(statusbar);

connect(labelWidget, SIGNAL(keyPressed(int)), this, SLOT(keyPressOnLabel(int )));
connect(this, SIGNAL(updateStatusBar(const QString& ,int)), statusbar, SLOT(showMessage(const QString&, int )));

if( qApp ) {
connect(qApp, SIGNAL(focusChanged(QWidget *, QWidget *)), this, SLOT(applicationFocusChanged(QWidget*, QWidget*)));
}

resize(width+100, height+100);
}


QString MainWindow::updateMessage()
{

QString msg = "Current focus widget is ";
if( QApplication::focusWidget() ) {
QString name = QApplication::focusWidget()->objectName();
msg += "'";
msg += name ;
msg += "'";
} else {
msg += "NONE";
}
msg += " --- ";
msg += "\n";
msg += "Number of key presses = ";
msg += QString::number(labelKeypressCount);
return msg;
}


void MainWindow::applicationFocusChanged(QWidget* old, QWidget* current)
{
emit updateStatusBar(updateMessage(), 0);
}

void MainWindow::keyPressOnLabel(int updateCount)
{
labelKeypressCount=updateCount;
emit updateStatusBar(updateMessage(), 0);
}



#include <QDebug>

MyCustomLabel::MyCustomLabel(QWidget *parent) : QLabel(parent), countKeypresses(0)
{
setWordWrap(true);
}

void MyCustomLabel::mousePressEvent(QMouseEvent *ev)
{
qDebug() << "label clicked";
setFocus();
}

void MyCustomLabel::keyPressEvent(QKeyEvent *ev)
{
qDebug() << "label: key pressed";
countKeypresses++;
emit keyPressed(countKeypresses);
}