임베디드 관련 카테고리/Qt

Qt로 다운로드 매니저 구현하기: 진행 상태 및 자동 설치 기능

CBJH 2024. 10. 30.
728x90
반응형

이 글에서는 Qt를 사용해 다운로드 진행 상태를 표시하고 자동 설치 기능을 제공하는 다운로드 매니저를 구현하는 방법을 다룹니다. 이 프로젝트는 다운로드한 파일을 "installer" 디렉터리에 저장하고, 다운로드가 완료되면 자동으로 인스톨러를 실행합니다.

 

참고 코드 : QSimpleUpdater


프로젝트 소개

이 프로젝트는 GitHub Pages에 업로드된 **인스톨러 파일(installer.exe)**을 Qt 애플리케이션에서 다운로드하고, **프로그래스바(progress bar)**를 통해 진행 상태와 남은 시간을 UI로 보여줍니다.
사용자는 설정된 디렉터리에 다운로드된 파일을 자동으로 실행할 수 있습니다.


구현 목표

  • 프로그래스바로 다운로드 진행 상태 표시
  • 남은 시간 계산 및 표시
  • 인스톨러 다운로드 후 자동 실행
  • 사용자 정의 디렉터리에 파일 저장

1. 프로젝트 파일 구조

/project-root
│
├── main.cpp                  # 메인 프로그램 진입점
├── download_manager.cpp      # 다운로드 및 설치 코드
├── download_manager.h        # 다운로드 관련 헤더 파일
├── installer                 # 다운로드된 파일 저장 경로
└── installer_v1.0.0.exe      # 다운로드될 인스톨러 파일 (예시)

2. 깃헙 페이지(GitHub Pages) 설정

이 프로젝트는 GitHub Pages를 통해 호스팅된 인스톨러를 다운로드합니다. 테스트를 위해서는 다음과 같은 설정이 필요합니다:

1.GitHub 저장소 생성:

  • 공개 저장소를 만들고, **Settings > Pages**로 이동해 GitHub Pages를 활성화합니다.

2.인스톨러 파일 업로드:

  • 다운로드할 인스톨러 파일(installer.exe)을 저장소의 루트 경로 또는 서브 디렉터리에 업로드합니다.
/v1.0.0/installer.exe

3.GitHub Pages 배포 완료 후 URL 확인:

  • 인스톨러의 URL을 기억합니다. 예:
https://yourusername.github.io/yourrepository/v1.0.0/installer.exe

4.GitHub에 푸시(push):

  • 파일 업로드 후 저장소에 푸시합니다.

3. 코드 작성 및 수정

📄 download_manager.h (헤더 파일)

#ifndef DOWNLOAD_MANAGER_H
#define DOWNLOAD_MANAGER_H

#include <QWidget>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QProgressBar>
#include <QLabel>
#include <QString>

class Downloader : public QWidget {
    Q_OBJECT

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

    void startDownload(const QUrl &url);
    void setFileName(const QString &file);
    void setDownloadDir(const QString &downloadDir);
    QString downloadDir() const;

private slots:
    void updateProgress(qint64 received, qint64 total);
    void finished();
    void calculateTimeRemaining(qint64 received, qint64 total);

private:
    QNetworkAccessManager *m_manager;
    QNetworkReply *m_reply;
    QString m_fileName;
    QString m_downloadDir;
    qint64 m_startTime;
    QProgressBar *m_progressBar;
    QLabel *m_timeLabel;
    QLabel *m_downloadLabel;
    void saveFile(qint64 received, qint64 total);
};

#endif // DOWNLOAD_MANAGER_H

📄 download_manager.cpp (다운로드 매니저 구현)

#include "download_manager.h"
#include <QVBoxLayout>
#include <QMessageBox>
#include <QDesktopServices>
#include <QDateTime>
#include <QDir>
#include <QFile>

Downloader::Downloader(QWidget *parent)
    : QWidget(parent), m_manager(new QNetworkAccessManager(this)), m_reply(nullptr) {
    setWindowTitle(tr("Installer Download Manager"));

    // UI 설정
    m_progressBar = new QProgressBar(this);
    m_timeLabel = new QLabel(tr("Time remaining: Unknown"), this);
    m_downloadLabel = new QLabel(tr("Downloading updates..."), this);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(m_downloadLabel);
    layout->addWidget(m_progressBar);
    layout->addWidget(m_timeLabel);
    setLayout(layout);

    // 디렉터리 생성
    QDir dir("installer");
    if (!dir.exists()) {
        dir.mkpath(".");
    }
    m_downloadDir = dir.absolutePath();
}

Downloader::~Downloader() {
    delete m_reply;
    delete m_manager;
}

void Downloader::startDownload(const QUrl &url) {
    m_progressBar->setValue(0);
    m_downloadLabel->setText(tr("Downloading updates..."));
    m_timeLabel->setText(tr("Time remaining: Unknown"));

    QNetworkRequest request(url);
    m_reply = m_manager->get(request);
    m_startTime = QDateTime::currentDateTime().toSecsSinceEpoch();

    connect(m_reply, &QNetworkReply::downloadProgress, this, &Downloader::updateProgress);
    connect(m_reply, &QNetworkReply::finished, this, &Downloader::finished);

    show();
}

void Downloader::setFileName(const QString &file) {
    m_fileName = file.isEmpty() ? "installer_v1.0.0.exe" : file;
}

void Downloader::setDownloadDir(const QString &downloadDir) {
    m_downloadDir = downloadDir;
}

QString Downloader::downloadDir() const {
    return m_downloadDir;
}

void Downloader::updateProgress(qint64 received, qint64 total) {
    if (total > 0) {
        m_progressBar->setMaximum(100);
        m_progressBar->setValue((received * 100) / total);
        calculateTimeRemaining(received, total);
    }
}

void Downloader::calculateTimeRemaining(qint64 received, qint64 total) {
    uint elapsed = QDateTime::currentDateTime().toSecsSinceEpoch() - m_startTime;
    if (elapsed > 0) {
        qreal speed = received / elapsed;
        qreal remainingTime = (total - received) / speed;

        QString timeString;
        if (remainingTime > 3600) {
            timeString = tr("about %1 hours").arg(int(remainingTime / 3600));
        } else if (remainingTime > 60) {
            timeString = tr("about %1 minutes").arg(int(remainingTime / 60));
        } else {
            timeString = tr("%1 seconds").arg(int(remainingTime));
        }

        m_timeLabel->setText(tr("Time remaining: %1").arg(timeString));
    }
}

void Downloader::saveFile(qint64 received, qint64 total) {
    Q_UNUSED(received);
    Q_UNUSED(total);

    QFile file(m_downloadDir + "/" + m_fileName);
    if (file.open(QIODevice::WriteOnly | QIODevice::Append)) {
        file.write(m_reply->readAll());
        file.close();
    }
}

void Downloader::finished() {
    if (m_reply->error() != QNetworkReply::NoError) {
        QMessageBox::critical(this, tr("Error"), tr("Download failed!"));
        return;
    }

    saveFile(0, 0);
    m_reply->deleteLater();

    QMessageBox::information(this, tr("Download Complete"), tr("Installer downloaded successfully!"));

    // 인스톨러 실행
    QDesktopServices::openUrl(QUrl::fromLocalFile(m_downloadDir + "/" + m_fileName));
    close();
}

📄 main.cpp (메인 프로그램)

#include 
#include "download_manager.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    Downloader downloader;
    downloader.setFileName("installer_v1.0.0.exe");
    downloader.startDownload(QUrl("https://yourusername.github.io/yourrepository/v1.0.0/installer.exe"));

    return app.exec();
}

4. 코드 수정 방법

1.다운로드 URL 변경:

  • main.cpp에서 다운로드할 인스톨러 파일의 URL을 변경합니다:
downloader.startDownload(QUrl("https://yourusername.github.io/yourrepository/v1.0.0/installer.exe"));

2.파일 이름 변경:

  • 다운로드된 파일의 이름을 설정합니다:
downloader.setFileName("installer_v1.0.0.exe");

3.저장 경로 변경:

  • download_manager.cpp에서 저장할 디렉터리를 변경합니다:
QDir dir("your_custom_directory");

5. 마무리

이제 Qt로 다운로드 매니저를 구현하여, GitHub Pages에서 파일을 다운로드하고 진행 상태를 표시할 수 있습니다. 코드를 적절히 수정해 다른 파일이나 URL로도 쉽게 테스트할 수 있습니다.
추가 질문이 있거나 도움이 필요하면 언제든지 문의하세요

댓글