Проект GUI в QT Creator не работает после того, как он повозился с ним - PullRequest
0 голосов
/ 25 октября 2019

Сложили какой-то скрипт из фрагментов другого скрипта. Я пытаюсь создать графический интерфейс для сценария Python (HHDB.py), который расшифровывает резервную копию. Для этого сценария требуются параметры, такие как пароль, местоположение папки с зашифрованными файлами и место назначения для записи зашифрованных файлов.

Использовал QT Creator, чтобы создать приятный графический интерфейс с кнопкой для просмотра папки с зашифрованными файлами. Путь этого показан в поле textedit. То же самое для пункта назначения. Тогда есть поле для ввода известного пароля. Наконец есть кнопка для запуска HHBD-скрипта с параметрами password, origin и destination location.

Поскольку я понятия не имею, где все идет не так, и отладчик не выдает ошибок (больше), мне нуженкодеры обращают внимание на мои (многие) недостатки.

Спасибо, что уже взглянули на код ниже:

Гуглил много, но многие найденные решения давали ошибки для отладки, ищитеи замените: - (

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QDir>
#include <QString>
#include <QLabel>
#include <QProcess>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;

}

void MainWindow::on_pushButton_clicked()
{

    QString backup_dir = QFileDialog::getExistingDirectory(this,tr("Choose HiSuite Backup Folder"), QDir::homePath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
    ui->textEdit->setPlainText(backup_dir.replace('/','\\'));
}

void MainWindow::on_pushButton_2_clicked()
{

    QString destination_dir = QFileDialog::getExistingDirectory(this,tr("Choose Destination Folder"), QDir::homePath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
    ui->textEdit_2->setPlainText(destination_dir.replace('/','\\'));

}

void MainWindow::on_pushButton_3_clicked()
{
    QString passwordstring = ui->password->toPlainText();

    QProcess process;
    QString scriptFile =  QCoreApplication::applicationDirPath() + "./HHBD.py";

    QString pythonCommand = "python " + scriptFile +
                        " passwordstring" +
                        " backup_dir.replace('/','\\')" +
                        " destination_dir.replace('/','\\')";

    printf("PyCommand: %s\n", pythonCommand.toStdString().c_str());
    process.start (pythonCommand);

}

Я хотел бы нажать «pushButton_3», сценарий выполняет сценарий HHBD.py с заданными параметрами, например, «python HHBD.py 123456789 C: \ test \ c: \ dest». «где« 123456789 »происходит из поля пароля,« C: \ test \ »- из поля backup_dir, а« C: \ dest »- из поля destination_dir

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_pushButton_3_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>395</width>
    <height>303</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Huawei HiSuite Backup Decrypter</string>
  </property>
  <property name="windowIcon">
   <iconset>
    <normaloff>J:/Downloads_2/huawei.png</normaloff>J:/Downloads_2/huawei.png</iconset>
  </property>
  <property name="autoFillBackground">
   <bool>true</bool>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>10</y>
      <width>151</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>Select HiSuite Backup Folder</string>
    </property>
   </widget>
   <widget class="QTextEdit" name="textEdit">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>40</y>
      <width>381</width>
      <height>23</height>
     </rect>
    </property>
    <property name="sizePolicy">
     <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
      <horstretch>0</horstretch>
      <verstretch>0</verstretch>
     </sizepolicy>
    </property>
    <property name="verticalScrollBarPolicy">
     <enum>Qt::ScrollBarAlwaysOff</enum>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton_2">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>70</y>
      <width>151</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>Select Destination Folder</string>
    </property>
   </widget>
   <widget class="QTextEdit" name="textEdit_2">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>100</y>
      <width>381</width>
      <height>21</height>
     </rect>
    </property>
    <property name="verticalScrollBarPolicy">
     <enum>Qt::ScrollBarAlwaysOff</enum>
    </property>
   </widget>
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>150</y>
      <width>381</width>
      <height>31</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>10</pointsize>
     </font>
    </property>
    <property name="autoFillBackground">
     <bool>true</bool>
    </property>
    <property name="lineWidth">
     <number>2</number>
    </property>
    <property name="text">
     <string>Type here the password given during the creation of the backup of the mobile device with Huawei HiSuite.</string>
    </property>
    <property name="wordWrap">
     <bool>true</bool>
    </property>
   </widget>
   <widget class="QTextEdit" name="password">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>190</y>
      <width>191</width>
      <height>21</height>
     </rect>
    </property>
    <property name="verticalScrollBarPolicy">
     <enum>Qt::ScrollBarAlwaysOff</enum>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton_3">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>220</y>
      <width>151</width>
      <height>31</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="text">
     <string>Decrypt HiSuite Backup</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_2">
    <property name="geometry">
     <rect>
      <x>270</x>
      <y>170</y>
      <width>141</width>
      <height>111</height>
     </rect>
    </property>
    <property name="text">
     <string/>
    </property>
    <property name="pixmap">
     <pixmap>J:/Downloads_2/Aantekening 2019-10-24 141833.png</pixmap>
    </property>
   </widget>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

1 Ответ

0 голосов
/ 27 октября 2019

Это такая маленькая программа, что нет смысла распределять ее по трем файлам. Вы можете поместить все это в main.cpp.

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

Это выглядит так:

screenshot of the example application

Сначала давайте начнем с главного окна,Вам не нужно использовать 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"

На этом пример завершается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...