Desktop Qt-Applications를 위한 글로벌 단축키shortcut/핫키hotkey 입니다.
QHotkey는 핫키/글로벌 단축키를 만드는 데 사용할 수 있는 클래스로, 애플리케이션 상태와 무관하게 어디에서나 작동하는 단축키입니다.
즉, 애플리케이션이 활성화, 비활성화, 최소화 또는 전혀 표시되지 않더라도 단축키를 받을 수 있습니다.
특징
Windows, Mac 및 X11에서 작동합니다.
사용이 간편하고 QKeySequence를 사용하여 간편한 단축키 입력이 가능합니다.
거의 모든 일반 키 지원(OS 및 키보드 레이아웃에 따라 다름)
키/수정자 조합을 직접 입력할 수 있습니다.
동일한 단축키에 대해 여러 QHotkey 인스턴스 지원(최적화 포함)
스레드 안전 - 모든 스레드에서 사용 가능(스레드 안전 섹션 참조)
필요한 경우 기본 키코드 및 수정자 사용 허용
참고: 현재 Wayland는 지원되지 않습니다. Wayland로 글로벌 단축키를 등록할 수 없기 때문입니다. 자세한 내용이나 Wayland에서 단축키를 작동시키는 방법에 대한 아이디어는 Issue #14 를 참조하세요.
빌딩
QHotkey는 Qt6와 Qt5를 모두 지원합니다. Qt6를 사용하는 경우 버전 6.2.0 이상이 필요합니다. CMake 빌드 시스템을 사용하여 빌드할 수 있습니다.
CMake
CMake QT_DEFAULT_MAJOR_VERSION 변수는 빌드에 사용되는 Qt의 주요 버전을 제어하며 기본값은 5입니다. 예를 들어, Qt6로 빌드하려면 CMake 명령줄 옵션 -DQT_DEFAULT_MAJOR_VERSION=6을 사용합니다. 테스트 애플리케이션 QHotkeyTest를 빌드하려면 -DQHOTKEY_EXAMPLES=ON을 지정합니다.
Windows 사용자에게 중요: QPM 버전 0.10.0(웹사이트에서 다운로드할 수 있는 버전)은 현재 Windows에서 작동하지 않습니다! 마스터에서 이미 수정되었지만 아직 출시되지 않았습니다. 새 버전이 출시될 때까지 여기에서 최신 개발 빌드를 다운로드할 수 있습니다.
이렇게 하면 QHotkey의 모든 경고가 꺼집니다(지금은 경고만 사용하므로 이것으로 충분합니다). 로깅 범주로 할 수 있는 모든 작업에 대한 자세한 내용은 Qt 문서를 확인하세요.
스레드 안전성
QHotkey 클래스 자체는 재진입 가능합니다. 즉, 모든 스레드에서 필요한 만큼 많은 인스턴스를 만들 수 있습니다. 이를 통해 모든 스레드에서 QHotkey를 사용할 수 있습니다. 하지만 인스턴스가 속한 스레드와 다른 스레드에서는 QHotkey 인스턴스를 사용해서는 안 됩니다! 내부적으로 시스템은 핫키 이벤트를 처리하고 이를 QHotkey 인스턴스에 분배하는 싱글톤 인스턴스를 사용합니다. 이 내부 클래스는 완전히 스레드 안전합니다.
그러나 이 싱글톤 인스턴스는 메인 스레드에서만 실행됩니다. (한 가지 이유는 일부 OS 함수가 스레드 안전하지 않기 때문입니다.) 스레드 핫키를 가능하게 하기 위해 중요한 함수(핫키 등록/등록 해제 및 키 변환)도 모두 메인 스레드에서 실행됩니다. 다른 스레드의 QHotkey 인스턴스는 Qt::BlockingQueuedConnection과 함께 QMetaObject::invokeMethod를 사용합니다.
여러분에게 이는 다음을 의미합니다. 메인 스레드가 아닌 다른 스레드의 QHotkey 인스턴스는 핫키를 등록/등록 해제/변환하는 데 약간 더 오래 걸릴 수 있습니다. 메인 스레드가 이를 대신 수행할 때까지 기다려야 하기 때문입니다. 중요: 그러나 이 기능에는 한 가지 추가 제한이 있습니다. 메인 스레드가 아닌 다른 스레드의 QHotkey 인스턴스는 메인 이벤트 루프가 끝나기 전에 등록 해제되거나 파괴되어야 합니다. 그렇지 않으면 핫키 파괴 시 애플리케이션이 중단됩니다. 이 제한은 메인 스레드의 인스턴스에는 적용되지 않습니다. 또한 루프가 시작되기 전에 단축키를 변경하거나 등록/등록 해제하는 경우에도 실제로 시작될 때까지 동일한 일이 발생합니다.
문서는 doxygen 을 사용하여 작성되었습니다. 여기에는 HTML 문서와 Qt-Help 파일이 포함되어 있으며, 이를 QtCreator(QtAssistant)에 포함시켜 F1-Help를 표시할 수 있습니다(자세한 내용은 외부 문서 추가를 참조하세요).
기술적
요구 사항
명시적 지원은 최신 Qt LTS에만 제공되지만 이전 버전에서도 작동할 수 있습니다.
최소한 QtGui-Module(QGuiApplication). 콘솔 기반 애플리케이션의 단축키는 지원되지 않습니다(운영 체제에서). 그러나 보이는 창 없이 GUI 애플리케이션을 만들 수 있습니다.
C++11
알려진 제한 사항
단일 키/수정자 조합만 가능합니다. QKeySequence를 사용하는 경우 시퀀스의 첫 번째 키+수정자만 사용됩니다.
Qt::Key는 일반 숫자와 숫자패드 숫자 사이에 차이를 두지 않습니다. 그러나 대부분의 키보드는 이것을 요구합니다. 따라서 네이티브 단축키를 사용하지 않는 한 숫자패드에 대한 단축키를 등록할 수 없습니다.
모든 키를 지원하지는 않지만, 일반적인 키는 대부분 지원합니다. 플랫폼 간에 차이가 있으며 키보드 레이아웃에 따라 달라집니다. 예를 들어 "Delete"는 Windows와 Mac에서는 작동하지만 X11에서는 작동하지 않습니다(적어도 제 테스트 머신에서는 그렇습니다). 가능한 한 OS 함수를 사용하려고 했지만, Qt::Key 값을 네이티브 키로 변환해야 하기 때문에 몇 가지 제한이 있습니다. 필요한 키를 사용할 수 있으므로 네이티브 단축키를 사용해 보세요.
등록된 키는 QHotkey에서 "취득"됩니다. 즉, 핫키가 애플리케이션에서 사용된 후에는 활성 애플리케이션으로 전송되지 않습니다. 이는 운영 체제에서 이런 방식으로 수행되며 변경할 수 없습니다.
X11에서 QHotkey: Failed to register hotkey. Error: BadAccess (attempt to access private resource denied) 오류가 발생하는 경우 X11에 개인용 핫키를 등록하려고 한다는 의미입니다. 이러한 키는 일반 API를 사용하여 등록할 수 없습니다.
첫 번째 미들웨어로도 사용할 수 있습니다(이미 기록 등을 수행하는 첫 번째 미들웨어가 있는 경우)
app.use([](auto &ctx, auto next, auto prev)
{
next([&ctx, prev]
{
// this is last code to be called before sending response to client
if(ctx.response.status() == 404)
ctx.response.body("Custom Not Found");
prev();
});
});
프로젝트에서 qt-mustache를 사용하려면 mustache.h 및 mustache.cpp 파일을 프로젝트에 추가하기만 하면 됩니다.
라이센스
qt-mustache는 BSD 라이센스에 따라 라이센스가 부여되었습니다.
종속성
qt-mustache는 QtCore 라이브러리에 따라 다릅니다. Qt 5 및 Qt 6과 호환됩니다.
용법
구문
qt-mustache는 표준 Mustache 구문을 사용합니다. 자세한 내용은 Mustache 매뉴얼 을 참조하세요.
데이터 소스
Qt-mustache은 mustache의 값을 사용하여 mustache 태그를 확장합니다::Context. Mustache::QtVariantContext는 QVariantHash 또는 QVariantMap을 감싸는 간단한 컨텍스트 구현입니다. 사용자 지정 데이터 소스를 사용하여 템플릿을 렌더링하려는 경우 데이터 소스를 미러링하는 QVariantHash를 만들거나 Nowsters::Context를 다시 구현할 수 있습니다.
부분
{{>partial}} Mustache 태그가 발견되면 qt-mustache는 Mustache::PartialResolver를 사용하여 partial을 로드하려고 시도합니다.
컨텍스트에서 제공됩니다. Mustache::PartialMap은 부분 이름의 QHash<QString,QString> 맵을 취하는 간단한 리졸버입니다.
값으로 이동하고 해당 맵에서 부분을 찾습니다. Mustache::PartialFileLoader는 또 다른 간단한 리졸버입니다.
지정된 디렉토리의 <partial name>.mustache 파일에서 부분을 가져옵니다.
사용자 정의 소스에서 파셜을 로드하려면 Mustache::PartialResolver 인터페이스를 다시 구현할 수 있습니다.
(예: 데이터베이스).
오류 처리
템플릿을 렌더링하는 동안 오류가 발생하면 Mustache::Renderer::errorPosition()이 음수가 아닌 값으로 설정됩니다.
템플릿 렌더링이 중지됩니다. 부분 템플릿을 렌더링하는 동안 오류가 발생하면 errorPartial()에 이름이 포함됩니다.
부분적인 것의.
람다
Mustache 매뉴얼 은 렌더링을 사용자 정의하는 메커니즘을 제공합니다.
태그의 값을 호출 가능한 객체(예: Ruby 또는 Javascript의 람다)로 설정하여 템플릿 섹션을 만듭니다.
렌더링되지 않은 텍스트 블록을 템플릿 섹션으로 가져와서 자체적으로 렌더링합니다. qt-mustache는 다음을 지원합니다.
Context::canEval() 및 Context::eval() 메서드를 통해 이를 수행할 수 있습니다.
Qt6에서는 QVariant::type() 메서드가 더 이상 권장되지 않으며, 대신 typeId() 또는 metaType()을 사용하는 것이 좋습니다. typeId()는 QVariant에 저장된 데이터의 QMetaType::Type을 반환하고, metaType()은 QMetaType 객체 자체를 반환합니다.
다음은 type()을 typeId() 또는 metaType()으로 대체하는 방법입니다.
기존 코드(Qt5):
QVariant value = ...;
QVariant::Type type = value.type();
수정된 코드(Qt6):
typeId() 사용: QVariant의 타입을 QMetaType::Type 형태로 반환합니다.
QMetaType::Type type = static_cast<QMetaType::Type>(value.typeId());
metaType() 사용: QMetaType 객체 자체를 사용하여 타입을 확인할 수 있습니다.
QMetaType metaType = value.metaType();
if (metaType == QMetaType::fromType<int>()) {
// int 타입일 경우 처리
}
이렇게 typeId()와 metaType()을 사용하여, 더 이상 type() 함수를 호출할 때 나타나는 경고를 해결할 수 있습니다.
Qt6에서는 QStyleOptionHeader::init() 함수가 더 이상 존재하지 않습니다. 대신 QStyleOptionHeader 객체를 초기화할 때, 직접 QStyleOption의 기본 초기화 함수인 QStyleOption::initFrom()을 사용하는 방식으로 대체할 수 있습니다. 이를 통해 헤더의 스타일 옵션을 위젯으로부터 초기화할 수 있습니다.
다음은 QStyleOptionHeader::init()을 대체하는 방법입니다.
기존 코드(Qt5):
QStyleOptionHeader option;
option.init(widget);
수정된 코드(Qt6):
QStyleOptionHeader option;
option.initFrom(widget); // initFrom을 사용해 위젯으로부터 초기화
이처럼 initFrom 메서드를 사용하면 widget의 상태와 속성을 사용하여 option을 초기화할 수 있습니다.
Qt6에서는 qSort가 더 이상 사용되지 않습니다. 대신 C++ 표준 라이브러리에서 제공하는 std::sort를 사용해야 합니다. Qt5까지는 qSort가 제공되었으나, Qt6부터는 이를 표준 C++ 정렬 함수로 대체해야 합니다.
기존 코드(Qt5):
QVector list;
qSort(list.begin(), list.end());
수정된 코드(Qt6, C++ 표준 라이브러리 사용):
std::sort(list.begin(), list.end());
qSort는 Qt의 전용 함수였지만, C++11 이후로 std::sort가 더 널리 사용되고 권장되므로 Qt6에서는 std::sort를 사용하는 것이 적절합니다.
2. QList를 정렬하는 경우
정렬하려는 값이 QList의 경우, Qt6에서는 std::sort를 사용할 수 없습니다. QList는 기본적으로 std::vector와 같은 임의 접근(iterable) 반복자를 제공하지 않기 때문에, std::sort와 같은 알고리즘에 사용할 수 없습니다. 대신, QList의 멤버 함수인 sort()를 직접 사용할 수 없기 때문에 다른 방식으로 정렬을 구현해야 합니다.
QList 정렬 방법:
QList를 QVector로 변환 후 정렬: QList를 QVector로 변환한 다음, std::sort를 적용한 후 다시 QList로 변환하는 방법이 있습니다.
QVector<int> vec = list.toVector();
std::sort(vec.begin(), vec.end());
list = QList<int>::fromVector(vec);
QList::operator< 사용: 만약 간단한 정렬 기준을 적용하려면 QList의 operator<를 이용하여 std::sort 대신 QList의 sort() 함수를 이용할 수 있습니다.
람다 함수 사용: 만약 특정 기준으로 정렬하고 싶다면, 람다 함수를 이용할 수 있습니다. 이를 통해 QVector로 변환하지 않고도 직접 원하는 방식으로 비교 연산을 할 수 있습니다.
일반적으로 QList보다는 QVector나 std::vector와 같은 컨테이너를 사용하는 것이 더 효율적일 수 있으므로, 상황에 따라 데이터 구조를 변경하는 것도 고려해 볼 수 있습니다.
데이터는 QHexDocument 클래스를 통해 QHexView에서 관리됩니다.
다양한 버퍼 백엔드를 사용하여 QHexDocument의 fromDevice() 메서드를 사용하여 일반적인 QIODevice를 로드하는 것이 가능합니다.
QFile을 메모리 내 버퍼로 로드하기 위해 도우미 메서드가 제공됩니다.
#include <QHexView/qhexview.h>
QHexOptions options;
options.grouplength = 2; // Pack bytes as AABB
options.bytecolors[0x00] = {Qt::lightGray, QColor()}; // Highlight '00's
options.bytecolors[0xFF] = {Qt::darkBlue, QColor()}; // Highlight 'FF's
hexview.setOptions(options);
QHexDocument* document = QHexDocument::fromMemory<QMemoryBuffer>(bytearray); /* Load data from In-Memory Buffer... */
//QHexDocument* document = QHexDocument::fromDevice<QMemoryBuffer>(iodevice); /* ...from a generic I/O device... */
//QHexDocument* document = QHexDocument::fromFile<QMemoryBuffer>("data.bin"); /* ...or from File... */
QHexView* hexview = new QHexView();
hexview->setDocument(document); // Associate QHexEditData with this QHexEdit (ownership is not changed)
// Document editing
QByteArray data = document->read(24, 78); // Read 78 bytes starting to offset 24
document->insert(4, "Hello QHexEdit"); // Insert a string to offset 4
document->remove(6, 10); // Delete bytes from offset 6 to offset 10
document->replace(30, "New Data"); // Replace bytes from offset 30 with the string "New Data"
// Metatadata management (available from QHexView too)
hexview->setBackground(5, 10, Qt::Red); // Highlight background at offset range [5, 10)
hexview->setForeground(15, 30, Qt::darkBLue); // Highlight background at offset range [15, 30)
hexview->setComment(12, 42, "I'm a comment!"); // Add a comment at offset range [12, 42)
hexview->unhighlight(); // Reset highlighting
hexview->clearMetadata(); // Reset all styles