Это такая маленькая программа, что нет смысла распределять ее по трем файлам. Вы можете поместить все это в main.cpp
.
Пример ниже является полным и компилируемым. Весь файл длиной 129 строк. Вы можете скачать полный проект с https://github.com/KubaO/stackoverflown/tree/master/questions/script-frontend-58555092.
Это выглядит так:

Сначала давайте начнем с главного окна,Вам не нужно использовать QMainWindow
, поскольку он предназначен для "больших" приложений с меню и т. Д. Все, что вам нужно, это простой QWidget
:
// https://github.com/KubaO/stackoverflown/tree/master/questions/script-frontend-58555092
#include <QtWidgets>
#include <initializer_list>
class MainWindow : public QWidget {
Q_OBJECT
Экземпляр QProcess
сохраняется на весь срок службыокна, так что вместо запуска отдельного процесса мы можем отслеживать его состояние и вывод:
QProcess process;
Пользовательский интерфейс настолько прост, что его элементы могут быть легко предоставлены в виде элементов:
QGridLayout layout{this};
QPushButton selectSource{tr("Select HiSuite Backup Folder")};
QLineEdit source;
QPushButton selectDestination{tr("Select Destination Folder")};
QLineEdit destination;
QLabel instruction{tr(
"Type here the password given during the creation of "
"the backup of the mobile device with Huawei HiSuite.")};
QLineEdit password;
QPushButton decrypt{tr("Decrypt HiSuite Backup")};
QTextBrowser output;
QFileSystemModel fsModel;
QCompleter fsCompleter{&fsModel};
QTextCharFormat statusFormat, commandFormat, stdoutFormat, stderrFormat;
void setupUi();
void doDecrypt();
void onStateChanged(QProcess::ProcessState state);
public:
explicit MainWindow(QWidget *parent = nullptr);
};
Обратите внимание, что все видимые пользователем строки заключены в tr()
, чтобы их можно было легко перевести с помощью Qt Linguist.
Настройка пользовательского интерфейса разложена и довольно не вызывает сомнений. Поля ввода пути имеют завершающий файл файловой системы, чтобы было проще вводить пути вручную.
void MainWindow::setupUi() {
setWindowTitle(tr("Huawei HiSuite Backup Decrypter"));
QFont boldFont;
boldFont.setBold(true);
decrypt.setFont(boldFont);
instruction.setWordWrap(true);
commandFormat.setForeground(QColor(Qt::green).darker());
statusFormat.setForeground(QColor(Qt::blue));
stderrFormat.setForeground(QColor(Qt::red).darker());
int row = 0;
for (auto *widget : std::initializer_list<QWidget *>{
&selectSource, &source, &selectDestination, &destination, &instruction,
&password, &decrypt, &output}) {
layout.addWidget(widget, row++, 0);
}
for (auto *button : {&selectSource, &selectDestination, &decrypt})
button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
fsModel.setRootPath("");
fsModel.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
fsCompleter.setCompletionMode(QCompleter::PopupCompletion);
source.setCompleter(&fsCompleter);
destination.setCompleter(&fsCompleter);
}
Большинство слотов настолько малы, что могут быть предоставлены внутри лямбд:
MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
setupUi();
connect(&selectSource, &QPushButton::clicked, [this] {
auto dir = QFileDialog::getExistingDirectory(
this, tr("Choose HiSuite Backup Folder"), QDir::homePath(),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
source.setText(dir);
});
connect(&selectDestination, &QPushButton::clicked, [this] {
auto dir = QFileDialog::getExistingDirectory(
this, tr("Choose Destination Folder"), QDir::homePath(),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
destination.setText(dir);
});
connect(&decrypt, &QPushButton::clicked, this, &MainWindow::doDecrypt);
connect(&process, &QProcess::stateChanged, this, &MainWindow::onStateChanged);
Вывод процесса показан в текстовом браузере, раскрашенном для облегчения распознавания ошибок:
connect(&process, &QProcess::readyReadStandardOutput, [this] {
output.setCurrentCharFormat(stdoutFormat);
output.append(process.readAllStandardOutput());
});
connect(&process, &QProcess::readyReadStandardError, [this] {
output.setCurrentCharFormat(stderrFormat);
output.append(process.readAllStandardError());
});
}
Состояние процесса указано для полноты картины;
void MainWindow::onStateChanged(QProcess::ProcessState state) {
output.setCurrentCharFormat(statusFormat);
switch (state) {
case QProcess::Starting:
output.append(tr("(starting)"));
break;
case QProcess::Running:
output.append(tr("(started)"));
break;
case QProcess::NotRunning:
output.append(tr("(not running)"));
break;
}
}
Расшифровка устанавливает процесс и его аргументы в явном виде, используя свойства program
и arguments
QProcess
. Таким образом, нет проблем с пробелами в путях и т. Д. - Qt решает все проблемы за нас. Обратите внимание, что у applicationDirPath() + "./foo"
был период, который давал бы путь, подобный C:/path./foo
- такой путь недопустим, период не должен быть там.
void MainWindow::doDecrypt() {
output.clear();
auto password = this->password.text();
QString scriptFile = QCoreApplication::applicationDirPath() + "/HHBD.py";
process.setProgram("python");
process.setArguments({QDir::toNativeSeparators(scriptFile), password,
QDir::toNativeSeparators(source.text()),
QDir::toNativeSeparators(destination.text())});
output.setCurrentCharFormat(commandFormat);
output.setText(
QStringLiteral("%1 %2").arg(process.program()).arg(process.arguments().join(' ')));
process.start();
}
Функция main
отображает окно. Файл moc включен в конце, поскольку у нас нет отдельного заголовочного файла main.h
:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
#include "main.moc"
На этом пример завершается.