vcpkg로 설치한 Qt 라이브러리와 Qt Maintenance Tool(공식 Qt 설치 도구)로 설치한 Qt 라이브러리는 기술적으로 동시에 시스템에 존재할 수 있지만, 일반적인 프로젝트에서 동시에 함께 사용하는 것은 권장되지 않으며, 여러 문제가 발생할 수 있습니다.

주요 이유와 주의점은 다음과 같습니다:

  • 경로 충돌 및 우선순위 문제
    • CMake 프로젝트의 경우, vcpkg가 설치한 Qt가 CMAKE_PREFIX_PATH 등에서 우선적으로 인식되어, QtCreator에서 선택한 공식 Qt 버전 대신 vcpkg의 Qt가 자동으로 사용될 수 있습니다
    • QtCreator의 Kit 설정이나 Maintenance Tool로 설치한 Qt가 무시될 수 있습니다
  • Visual Studio 및 Qt VS Tools와의 호환성
    • Qt VS Tools(Visual Studio용 Qt 확장)는 vcpkg로 설치한 Qt의 폴더 구조와 공식 Qt 설치의 구조가 다르기 때문에, vcpkg로 설치한 Qt와 완벽하게 호환되지 않을 수 있습니다
    • 특히 디버그/릴리즈 라이브러리 경로, qmake.exe 위치, mkspecs 등에서 문제가 발생할 수 있습니다.
  • 라이브러리 버전 충돌
    • 두 설치 방식으로 서로 다른 Qt 버전이 설치되어 있다면, 프로젝트에서 예기치 않은 라이브러리 버전이 링크되어 런타임 오류가 발생할 수 있습니다.
    • 특히 Qt의 바이너리 호환성 정책에 따라, 일부 버전 간에는 혼용이 불가능할 수 있습니다.
  • 폴더 구조 및 경로 문제
    vcpkg로 설치한 Qt는 공식 Qt 설치와 폴더 구조와 경로가 다릅니다. 예를 들어, qmake.exe가 위치한 경로가 다르고, 라이브러리와 플러그인, mkspecs 등도 분리되어 있습니다
  • 디버그/릴리즈 라이브러리 분리
    vcpkg는 디버그와 릴리즈 라이브러리를 각각 다른 폴더에 저장하는 반면, 공식 Qt 설치에서는 동일 폴더에 저장하는 경우가 많아 빌드 환경에서 혼란이 생길 수 있습니다
  • 실제 사용 방법
    • 동시에 사용하는 것은 피하고, 하나의 방식(공식 설치 또는 vcpkg 설치)만 사용하는 것이 안정적입니다.
    • 특정 프로젝트에서는 vcpkg의 Qt를, 다른 프로젝트에서는 공식 설치 Qt를 사용하는 방식으로 분리할 수 있지만, 환경 변수 및 빌드 설정에 주의해야 합니다

결론:
vcpkg로 설치한 Qt와 Qt Maintenance Tool로 설치한 Qt는 동시에 시스템에 존재할 수 있지만, 동일한 프로젝트에서 함께 사용하는 것은 권장되지 않으며, 빌드 및 실행 환경에서 예기치 않은 문제가 발생할 수 있습니다. 프로젝트별로 한 가지 설치 방식만 사용하는 것이 가장 안전합니다.

 

참고

https://forum.qt.io/topic/157554/vs-tools-in-vs2022-do-not-work-with-vcpkg-installed-qt6

https://github.com/microsoft/vcpkg/issues/2643

https://forum.qt.io/topic/96818/integrate-qt-vs-tools-with-vcpkg-installed-qt

https://www.qtcentre.org/threads/71952-CMake-vcpkg-qt-takes-precedence-over-onlineinstaller-qt

Qt의 메타-오브젝트 시스템(meta-object system)객체간 통신을 위한 시그널-슬롯 매커니즘과, 런타임 타입 정보, 동적 속성 시스템을 제공한다.

 

메타-오브젝트 시스템은 아래 세 가지를 기반으로 한다:

1. QObject 클래스 : 객체를 위한 기반 클래스를 제공하여 메타-오브젝트 시스템의 이점을 이용할 수 있게 한다.

2. Q_OBJECT 매크로 : 클래스의 private 섹션 안에 선언되며, 동적 속성과 시그널 슬롯 등의 메타-오브젝트 기능을 사용할 수 있게 한다.

3. Meta-Object Compiler(moc) : QObject의 자식 클래스들에게 필요한 메타-오브젝트 구현 코드를 제공한다.

 

moc 툴은 C++ 헤더, 소스 파일 읽어 Q_OBJECT 매크로가 포함된 클래스를 찾고,

이를 찾으면 각 클래스에 대해 메타-오브젝트 코드를 포함하는 또다른 C++ 소스 파일을 생성해낸다.

이렇게 생성된 소스파일은 인클루드, 컴파일되고 클래스 구현과 링크되어 사용된다.

 

예) 헤더파일에 Q_OBJECT 매크로가 있는 클래스가 있다면,

메타-오브젝트를 이용할 수 있는 코드들을 추가한 새로운 헤더 파일을 만들어내고,

이 헤더 파일을 include한 새로운 C++ 구현 파일이 생겨 빌드시에는 이를 컴파일하고 링크하여 사용한다.

 

 

참고

https://doc.qt.io/qt-6/metaobjects.html

https://coding-chobo.tistory.com/9

QSQLITE DB에서 regexp를 사용하려면,

커넥션 열 때 setConnectOptions("QSQLITE_ENABLE_REGEXP=1"); 을 설정해 주어야 한다.

bool DB::connectDatabase()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "connName");
    db.setConnectOptions("ISC_DPB_LC_CTYPE=UTF-8");
    db.setConnectOptions("QSQLITE_ENABLE_REGEXP=1");
    db.setDatabaseName(":memory:");
    if (!db.isValid())
    {
        qDebug() << "addDatabase failed.(db is not valid)";
        return false;
    }
    if (!db.isOpen())
    {
        if (!db.open())
        {
            qDebug() << QString("DB Open Failed - connName : %1, dbname : %2").arg("connName").arg(":memory:");
            QSqlDatabase::removeDatabase("connName");
            return false;
        }
    }
    return true;
}

 

데이터를 조회할 때는, 아래와 같이 사용한다.

한글로 시작하는 데이터 조회

SELECT * FROM tablename WHERE `columnName` REGEXP '^[ㄱ-ㅎ가-힣]';

영어로 시작하는 데이터 조회

SELECT * FROM tablename WHERE `columnName` REGEXP '^[a-zA-Z]';

숫자로 시작하는 데이터 조회

SELECT * FROM tablename WHERE `columnName` REGEXP '^[0-9]';

일본어로 시작하는 데이터 조회

SELECT * FROM tablename WHERE `columnName` REGEXP '^[ぁ-んァ-ヶー一-龠]' ;

중국어로 시작하는 데이터 조회

SELECT * FROM tablename WHERE `columnName` REGEXP '^[一-龥]';

샘플 코드

void DB::select() {
    QSqlDatabase DB = QSqlDatabase::database("connName");    

    QSqlQuery sql(DB);
    QString query = "SELECT * FROM tablename WHERE `subject` REGEXP '^[ㄱ-ㅎ가-힣]'";
    bool re = sql.exec(query);
    while (sql.next()) {
        qDebug() << sql.value(0).toString();
    }    
}

1. 디렉토리가 비어있는지 체크

Qt 5.9 이후부터는 QDir 클래스의 isEmpty() 함수로 체크 가능하다.

QString directoryPath = "C:\Directory";
QDir dir(directoryPath);
if (dir.isEmpty())
	qDebug() << directoryPath << " is Empty!";
else
	qDebug() << directoryPath << " is not Empty!";

 

2. 디렉토리 안 파일 개수 카운팅

QDir 클래스의 count() 함수로 카운팅 가능하다.

다만, .(현재폴더) ..(부모 폴더) 두개가 자동으로 포함되어 카운팅 되기 때문에, 이들을 빼주어야 한다.

QString directoryPath = "C:\Directory";
QDir dir(directoryPath);
dir.setFilter( QDir::AllEntries | QDir::NoDotAndDotDot ); // 현재, 부모 폴더 빼주기
qDebug() << directoryPath << " contains << dir.count() << " files.";

읽기 전용 파일은 덮어쓰거나, 삭제가 안된다. 

 

이 때, 파일 퍼미션을 설정해서 읽기 전용 속성을 제거할 수 있다.

(파일에 쓰기 권한을 주면, 덮어쓰기나 삭제가 가능해진다.)

 

읽기 전용(Read Only) 파일에 쓰기 권한 주기

// C++ code
#include <QFile>

void removeReadOnly(QString filepath)
{
    QFile file(filepath);
    file.setPermissions(file.permissions() |
                        QFileDevice::WriteOwner |
                        QFileDevice::WriteUser |
                        QFileDevice::WriteGroup |
                        QFileDevice::WriteOther);
}

 

QPushButton의 background color를 설정하고/가져오는 방법입니다.

 

1. QPushButton의 background color 설정하기

QColor color(Qt::red);
ui->pushButton->setStyleSheet(QString("background-color: %1;").arg(color.name()));

 

2. QPushButton의 background color 가져오기

// C++ code
QColor Panel::buttonColor() const
{
    return ui->pushButton->palette().background().color();
}

QMessageBox 안에 html 태그를 포함한 텍스트를 쓰고 싶은 경우가 있다.

예) <strong> 태그를 써서 특정 글자를 진하게 표현하고 싶다던가, <h4> 등의 제목 태그를 쓰고 싶다던가, <br/> 태그를 써서 줄바꿈을 하고 싶다던가..

 

이럴 때에는 setTextFormat(Qt::RichText); 함수로, 텍스트 포맷을 RichText로 설정해 주면 된다.

QMessageBox msg(this);
msg.setIcon(QMessageBox::Information);
msg.setTextFormat(Qt::RichText);
msg.setWindowTitle(tr("Title"));
msg.setText(tr("<strong>Hello!</strong><br/>World!");
msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
if (msg.exec() == QMessageBox::Yes) {
	// do something on Yes
}
else {
	// do something on No
}

 

가끔, 위젯의 상태를 변경하지만, 변경시 발생하는 시그널은 블럭해야 하는 경우가 있다.

(변경 시그널은 발생시키지 않아야 하는 경우 = 변경 시그널에 connect 되어 있는 함수를 실행하면 안되는 경우)

이럴 경우, SignalBlocker를 사용하면 된다.

 

방법 1. blockSignals 함수 사용

blockSignals(True) blockSignals(False) 사이에서 실행되는 코드는 signal을 발생시키지 않는다.

 

아래는 checkBox에서, 시그널을 블럭하면서 체크 상태를 바꾸는 예이다.

# Python code
self.checkBox.blockSignals(True)
self.checkBox.toggle()
self.checkBox.blockSignals(False)

 

방법 2. QSignalBlocker 사용

위와 동일한 기능을 하는 QSignalBlocker라는 클래스를 사용할 수도 있다. 

중괄호 안에서 QSignalBlocker를 생성하면, 해당 범위 안에서 시그널을 막아준다.

  • 시그널 블럭 대상 : QSignalBlocker 인자로 넘어온 오브젝트 (예: 체크박스)
  • 시그널 블럭 범위 : QSignalBlocker 생성 후, 중괄호가 끝날때까지 (QSignalBlocker 가 생성된 후, 소멸되기 전까지 시그널을 막음)
// C++ code
#include <QSignalBlocker>

ui->checkBox->setChecked(true); // 시그널 발생함

if (wantToBlockSignal) 
{
    const QSignalBlocker blocker(ui->checkBox);	// if문 범위 내에서, ui->checkBox의 시그널을 block한다
    ui->checkBox->setChecked(false); // 시그널 발생 안함
}

ui->checkBox->setChecked(true); // 시그널 발생함

참고 : https://doc.qt.io/qt-5/qobject.html#blockSignals

 

+ Recent posts