
QT 위젯 및 QT Quick의 크로스 플랫폼 창 사용자 정의 프레임 워크. Windows, Linux 및 MacOS를 지원합니다.
당신은 우리의 불화 채널에 가입하여 우리와 의사 소통 할 수 있습니다. 더 많은 플랫폼과 앱에서 FramelessHelper 기능을 개선 / 구현하는 것에 대한 발견, 생각 및 아이디어를 공유 할 수 있습니다!
FramelessDialog 클래스가 추가되었습니다. 일반 QWidget 보다 QDialog 선호되는 경우 사용할 수 있습니다.WindowBorderPainter 클래스에 의해 그려져 공개적으로 노출되므로 창 테두리를 쉽게 그리는 방법을 변경할 수 있습니다.WindowBorder 요소가 추가되었습니다. 크로스 플랫폼 윈도우 테두리 장식기이며 FramelessHelper 요소없이 작동 할 수 있습니다.FramelessApplicationWindow 요소가 추가되었습니다. 표준 ApplicationWindow 요소의 간단한 래퍼이며 제목 표시 줄을 제거하고 창 테두리를 추가합니다.find_package 사용하여 FramelessHelper를 찾을 수 있습니다.






Qsynthesis 프레임 워크를 사용한 Vogen 편집기. 저장소 URL : https://gitee.com/functioner/qvogenclient.
각 플랫폼에 대한 추가 제한 사항이 있습니다. 아래 플랫폼 참고 섹션을 참조하십시오.
git clone --recursive https://github.com/wangwenx190/framelesshelper.git # "--recursive" is necessary to clone the submodules.
mkdir build # Please change to your own build directory!
cd build
cmake -DCMAKE_PREFIX_PATH= < YOUR_QT_SDK_DIR_PATH > -DCMAKE_INSTALL_PREFIX= < WHERE_YOU_WANT_TO_INSTALL > -DCMAKE_BUILD_TYPE=Release -GNinja < PATH_TO_THE_REPOSITORY >
cmake --build . --config Release --target all --parallel
cmake --install . --config Release --strip # Don't add "--strip" for MSVC/Clang-CL/Intel-CL toolchains!
# YOUR_QT_SDK_DIR_PATH: the Qt SDK directory, something like "C:/Qt/6.5.1/msvc2019_64" or "/opt/Qt/6.5.1/gcc_64". Please change to your own path!
# WHERE_YOU_WANT_TO_INSTALL: the install directory of FramelessHelper, something like "../install". You can ignore this setting if you don't need to install the CMake package. Please change to your own path!
# PATH_TO_THE_REPOSITORY: the source code directory of FramelessHelper, something like "../framelesshelper". Please change to your own path! Qt6_DIR 또는 Qt5_DIR 사용하여 CMAKE_PREFIX_PATH 대체 할 수도 있습니다.
cmake -DQt6_DIR=C:/Qt/6.5.1/msvc2019_64/lib/cmake/Qt6 [other parameters ...]
# Or
cmake -DQt5_DIR=C:/Qt/5.15.2/msvc2019_64/lib/cmake/Qt5 [other parameters ...] 하위 모듈을 클로닝 할 때 오류가 있으면 git submodule update --init --recursive --remote 프로젝트 디렉토리에서 실행하십시오. 해당 명령은 모든 하위 모듈을 다운로드하여 업데이트합니다. 다시 실패하면 마침내 성공할 때까지 여러 번 실행하십시오.
컴파일 및 설치가 완료되면 find_package(FramelessHelper REQUIRED COMPONENTS Core Widgets Quick) 명령을 사용하여 FramelessHelper 라이브러리를 찾아 링크 할 수 있습니다. 그러나 그렇게하기 전에 cmake가 CMAKE_PREFIX_PATH 또는 FramelessHelper_DIR 변수를 전달하여 FramelessHelper를 찾을 위치를 알고 있는지 확인하십시오. 예를 들면 : -DCMAKE_PREFIX_PATH=C:/my-cmake-packages;C:/my-toolchain;etc... 또는 -DFramelessHelper_DIR=C:/Projects/FramelessHelper/lib64/cmake/FramelessHelper . CMAKE 프로젝트의 하위 디렉토리로서 FramelessHelper를 구축하십시오. 지원되는 FramelessHelper 대상 이름은 FramelessHelper::Core , FramelessHelper::Widgets 및 FramelessHelper::Quick . 예제 코드 :
# Find Qt:
find_package (QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package (Qt ${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
# Find FramelessHelper:
find_package (FramelessHelper REQUIRED COMPONENTS Core Widgets)
# Create your target:
add_executable (demo)
# Add your source code:
target_sources (demo PRIVATE main.cpp)
# Link to Qt and FramelessHelper:
target_link_libraries (demo PRIVATE
Qt ${QT_VERSION_MAJOR} ::Widgets
FramelessHelper::Core
FramelessHelper::Widgets
) FramelessHelper의 빠른 모듈의 구문 강조 표시가 필요한 경우 QML_IMPORT_PATH 변수를 설정하십시오. 예제 코드 :
# This is the path where you want FramelessHelper's Quick plugin (it only contains the QML meta
# info and an optional dummy library, for QtCreator's QML tooling purpose, it's not the Quick
# module) to place. Please change to your own path!
# If you are using add_subdirectory() to include FramelessHelper directly, you can change it to
# "${PROJECT_BINARY_DIR}/imports" instead of the install location.
set (FRAMELESSHELPER_IMPORT_DIR "C:/packages/FramelessHelper/qml" )
list ( APPEND QML_IMPORT_PATH " ${FRAMELESSHELPER_IMPORT_DIR} " )
list ( REMOVE_DUPLICATES QML_IMPORT_PATH)
# Force cache refresh:
set (QML_IMPORT_PATH ${QML_IMPORT_PATH} CACHE STRING "Qt Creator extra QML import paths" FORCE) QWIDGET의 창 프레임을 사용자 정의하려면 FramelessWidgetsHelper 객체를 인스턴스화 한 다음 위젯의 최상위 레벨 위젯에 연결 한 다음 FramelessWidgetsHelper 나머지 모든 작업을 수행합니다. Window 프레임은 상단 레벨 위젯에 성공적으로 연결되면 자동으로 제거됩니다. 이론적으로 동일한 위젯에 대해 여러 FramelessWidgetsHelper 객체를 인스턴스화 할 수 있습니다.이 경우 기능을 유지하는 객체는 하나 뿐이며 다른 모든 객체는 해당 래퍼가됩니다. 그러나 모든 것이 순조롭고 정상적으로 진행되도록하려면 어쨌든 그렇게해서는 안됩니다. FramelessWidgetsHelper 객체를 인스턴스화하는 가장 간단한 방법은 정적 메소드를 FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *) 호출하는 것입니다. 이전에 인스턴스화 된 객체의 핸들을 반환하거나 찾을 수없는 경우 새 객체를 인스턴스화합니다. 동일한 위젯에 대해이 방법을 여러 번 호출하는 것이 안전합니다. 이미 새로운 개체가 있으면 새 객체를 인스턴스화하지 않습니다. 또한 최상위 위젯이 동일하다면 그 기능을 언제 어디서 호출하는지는 중요하지 않습니다. 내부적으로 생성 된 객체는 항상 최상위 위젯으로 양육됩니다. FramelessWidgetsHelper 객체의 손잡이를 얻으면 void FramelessWidgetsHelper::extendsContentIntoTitleBar() 호출하여 운영 체제가 제공 한 기본 제목 표시 줄을 숨길 수 있습니다. FramelessWidgetsHelper 올바른 최상위 위젯을 찾을 수 있도록하려면 루트 상위가 최상위 상위 위젯 인 완전한 부모 체인이있는 위젯에서 FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *) 함수를 호출해야합니다. 프레임리스 창을 끌기 쉽게 만들려면 수제 제목 바 위젯을 직접 제공해야합니다. 제목 바 위젯은 직사각형 모양 일 필요가 없으며 창의 첫 번째 행에 배치 할 필요가 없습니다. void FramelessWidgetsHelper::setTitleBarWidget(QWidget *) 에 전화하여 FramelessHelper 제목 바 위젯이 무엇인지 알려주십시오. 기본적으로 타이틀 바 영역의 모든 위젯은 FramelessHelper에 의해 가로 채기 때문에 마우스 및 키보드 이벤트에 대한 책임이 없습니다. 책임 상태를 복구하기 위해서는 타격 테스트를 볼 수 있도록해야합니다. void FramelessWidgetsHelper::setHitTestVisible(QWidget* ) 에 전화하여 그렇게하십시오. 물론 제목 표시 줄 안에 있지 않은 위젯에서 전혀 부를 수 있습니다. 그래도 효과가 없습니다. QT의 자체 제한으로 인해 위젯에 루트 부모가 최상위 위젯 인 완전한 부모 체인이 있는지 확인해야합니다. FramelessWidgetsHelper 객체를 삭제하려고 시도하지 마십시오. 위젯을 모니터링하고 제어 할 수 있으며 QT는 자동으로 삭제됩니다. 메모리 누출에 대해 걱정할 필요가 없습니다.
FramelessWidget 과 FramelessMainWindow 라는 두 void FramelessWidgetsHelper::extendsContentIntoTitleBar() 클래스가 있으며, FramelessWidgetsHelper 의 단순한 포장지 일뿐입니다. 대신 일반 QWidget 절대적으로 사용할 수 있습니다.
우선, 매우 초기 단계 ( Q(Gui|Core)Application 개체를 구성하기 전에 필수 )에서 void FramelessHelper::Widgets::initialize() main 하십시오.
int main ( int , char **)
{
FramelessHelper::Widgets::initialize ();
// ...
}그런 다음 OS에서 제공하는 표준 타이틀 표시 줄을 숨 깁니다.
MyWidget::MyWidget (QWidget *parent) : QWidget(parent)
{
// You should do this early enough.
FramelessWidgetsHelper::get ( this )-> extendsContentIntoTitleBar ();
// ...
} 그런 다음 FramelessHelper 타이틀 바에 무엇이 있어야하는지 알려주십시오.
void MyWidget::myFunction ()
{
// ...
FramelessWidgetsHelper::get ( this )-> setTitleBarWidget (m_myTitleBarWidget);
// ...
}그런 다음 타이틀 막대 안에있는 위젯을 타격 테스트를 위해 볼 수 있도록하십시오.
void MyWidget::myFunction2 ()
{
// ...
FramelessWidgetsHelper::get ( this )-> setHitTestVisible (m_someSearchBox);
FramelessWidgetsHelper::get ( this )-> setHitTestVisible (m_someButton);
FramelessWidgetsHelper::get ( this )-> setHitTestVisible (m_someMenuItem);
// ...
} QT 위젯 응용 프로그램의 중요한 참고 사항 : FramelessHelper 창 지오메트리/플래그/상태 변경과 같은 창 사용자 정의 프로세스를 완료 한 경우에만 일부 기능을 사용할 수 있습니다. 이 경우 FramelessHelper 의 Public void ready() 신호에 연결하여 정확한 시점을 얻고 나중에 휴식 초기화 프로세스를 수행 할 수 있습니다.
우선, 당신은 매우 초기 단계에서 main 기능에서 void FramelessHelper::Quick::initialize() 호출해야합니다 ( Q(Gui|Core)Application 개체를 구성하기 전에 해야합니다 .
int main ( int , char **)
{
FramelessHelper::Quick::initialize ();
// ...
} 그런 다음 QML 엔진이 QML 문서를로드하기 전에 void FramelessHelper::Quick::registerTypes(QQmlEngine *) 호출하여 FramelessHelper 가 제공 한 사용자 정의 유형을 등록해야합니다.
int main ( int , char **)
{
// ...
QQmlApplicationEngine engine;
FramelessHelper::Quick::registerTypes (&engine);
// ...
} 이제 QML 문서를 작성할 수 있습니다. uri org.wangwenx190.FramelessHelper 에서 FramelessHelper 가져와야합니다. QT5를 사용하는 경우 바로 다음 버전 번호를 지정해야합니다.
import org.wangwenx190.FramelessHelper 1.0 // You can use "auto" or omit the version number in Qt6. 그런 다음 QML 유형 FramelessHelper 의 첨부 된 속성을 사용할 수 있습니다.
Window {
Item {
id : myTitleBar
Item { id : someControl1 }
Item { id : someControl2 }
Item { id : someControl3 }
Component . onCompleted : {
// Don't access FramelessHelper too early, otherwise it may not be able to find the root window!
FramelessHelper . titleBarItem = myTitleBar;
FramelessHelper . setHitTestVisible (someControl1);
FramelessHelper . setHitTestVisible (someControl2);
FramelessHelper . setHitTestVisible (someControl3);
}
}
} FramelessWidgetsHelper 인터페이스와 동일합니다. QML 유형 FramelessHelper 는 첨부 된 속성을 언제 어디서 사용하든 각 Window 에 대해 한 번만 인스턴스화됩니다. 그러나 FramelessHelper 유형의 특수 설계로 인해 일반 QML 유형처럼 사용할 수도 있습니다.
Window {
Item {
id : myTitleBar
Item { id : someControl1 }
Item { id : someControl2 }
Item { id : someControl3 }
Component . onCompleted : {
framelessHelper . setHitTestVisible (someControl1);
framelessHelper . setHitTestVisible (someControl2);
framelessHelper . setHitTestVisible (someControl3);
}
}
FramelessHelper {
id : framelessHelper
titleBarItem : myTitleBar
}
} 이론적으로 동일한 Window 에 대해 여러 개의 FramelessHelper 객체를 인스턴스화 할 수 있습니다.이 경우 그중 하나만 기능을 유지하고 다른 모든 객체는 래퍼가 될 것이지만 그렇게하는 것은 권장되지 않으며 예상치 못한 동작이나 버그를 유발할 수 있으므로 어떤 경우에도 그렇게하려고하지 마십시오.
호출 후 FramelessHelper 함수가 영향을 미치지 않는 경우, 가장 가능한 가장 가능한 이유는 FramelessHelper 의 특성을 호출/변경할 때 루트 창이 초기화 프로세스를 마치지 않았으므로 FramelessHelper 핸들을 얻을 수 없으므로 루트 창이 초기화를 마칠 때까지 사용자의 모든 작업이 무시됩니다.
FramelessWindow 라는 QML 유형도 있습니다. FramelessHelper 의 간단한 래퍼 일뿐입니다. 대신 Plain Window 절대적으로 사용할 수 있습니다.
QT 빠른 응용 프로그램의 중요한 참고 사항 : FramelessHelper 창 지오메트리/플래그/스테이트 변경과 같은 창 사용자 정의 프로세스를 완료 한 경우에만 일부 기능을 사용할 수 있습니다. 이 경우 FramelessHelper 의 Public void ready() 신호에 연결하여 정확한 시점을 얻고 나중에 휴식 초기화 프로세스를 수행 할 수 있습니다.
Window {
FramelessHelper . onReady : {
// do something here ...
}
} Window {
FramelessHelper {
onReady : {
// do something here ...
}
}
}보다 자세한 사용법을 보려면 데모 프로젝트를 참조하십시오 : 예제.
매우 드문 경우에 DWM 구성이 비활성화되면 (Windows 7에서만 가능) 왼쪽 상단 코너와 오른쪽 상단 코너가 둥근 모양으로 나타납니다. DWM 구성을 다시 활성화하면 둥근 모서리를 정사각형으로 복원 할 수 있습니다.
Frameless Windows가 수제 타이틀 바 위에 이상한 검은 색 바가있는 OpenGL 드라이버 버그가 있으며, 또한 창의 컨트롤이 일부 픽셀의 바닥 오른쪽 코너로 이동합니다. 그래픽 카드 드라이버, 특히 FramelessHelper가 아닌 OpenGL 드라이버의 버그입니다. 사용자가 제공하는 몇 가지 솔루션이 있지만 일부 솔루션은 모든 조건에서 작동하지 않을 수 있습니다.
| 해결책 | 원칙 |
|---|---|
| 그래픽 드라이버를 업그레이드하십시오 | 수정으로 배송 할 수있는 최신 드라이버를 사용해보십시오. |
| 시스템 테마를 "기본"으로 변경합니다 ( "Windows Aero"와 반대로) | Windows가 순수한 소프트웨어 렌더링을 사용하도록하십시오 |
| 여러 그래픽 카드가있는 경우 대신 다른 그래픽 카드를 사용하십시오. | 그런 버그가 전혀 없을 수있는 다른 드라이버를 사용하려고 노력하십시오. |
| 시스템을 최소한 Windows 11으로 업그레이드하십시오 | Windows 11은 더 이상 버그를 트리거 할 수 없도록 창 시스템을 재 설계했습니다. |
창에서 WS_THICKFRAME 및 WS_OVERLAPPED 스타일을 제거하고 동시에 WS_POPUP 스타일을 추가하고 WM_NCCALCSIZE 블록 내부에서 아무것도하지 않을 수도 있습니다 (전체 블록을 직접 false 하거나 전체 블록을 제거/댓글을 남기십시오). | QT의 FramelessWindowHint 의 행동을 반영하십시오 |
WM_NCCALCSIZE 트릭을 수행하는 대신 Qt::FramelessWindowHint 사용하십시오 | QT의 렌더링 코드 경로는이 두 솔루션간에 완전히 다릅니다. |
| QT가 Desktop OpenGL 대신 각도 백엔드를 사용하도록 강제 | 각도는 OpenGL 지시문을 D3D 지시문으로 변환합니다 |
| QT가 OpenGL을 통해 렌더링하는 대신 순수한 소프트웨어 렌더링을 사용하도록 강요 | QT는 OpenGL을 전혀 사용하지 않습니다 |
| QT가 일반 OpenGL 대신 MESA 3D 라이브러리를 사용하도록 강제 | 다른 OpenGL 구현을 사용하십시오 |
| OpenGL 대신 Direct3d/Vulkan/Metal을 사용하십시오 | 버기 OpenGL을 사용하지 마십시오 |
운이 좋으면 그들 중 하나가 문제를 해결할 수 있습니다. 그렇지 않은 경우 여러 솔루션을 함께 사용하려고 할 수 있습니다. 그러나 문제를 100% 고칠 수 있다고 보장 할 수는 없습니다.
Wind 1507 또는 1607과 같은 아주 오래된 Windows 10 버전 에서이 프레임 워크를 사용하려고하면 몇 가지 호환성 문제가있을 수 있습니다. Windows 7 에서이 프레임 워크를 사용하는 것도 지원되지만 권장하지 않습니다. 가장 안정적인 동작과 최고의 외관을 얻으려면 Windows 10 또는 Windows 11의 최신 버전에서 사용해야합니다.
스냅 레이아웃을 예상대로 작동시키기 위해 수제 시스템 버튼에 대한 추가 규칙이 있습니다.
setSystemButton() 호출하여 ( QWIDGET 또는 QQUICKITEM 일 수 있음) FramelessHelper를 최소화/최대화/닫기 버튼을 알리십시오.When running on Win10, it seems the top border is missing? But the demo applications still have it? FramelessHelper 상단 테두리를 포함하여 창 프레임의 전체 상단 부분을 제거하여 시스템 제목 표시 줄을 숨 깁니다. 시스템 제목 표시 줄 만 제거 할 수있는 방법은 없지만 동시에 상단 테두리를 유지하면서도 Microsoft조차도 그렇게 할 수 없습니다. 정확한 이유는 비 미묘한 개발자에게 알려지지 않았으며, 그 뒤에있는 모든 마법을 파는 데 관심이 없습니다. 따라서 상단 테두리가 여전히 존재하는 척하려면 수동으로 직접 그려야합니다. 공식 DWM API를 통해 높이와 색상을 검색 할 수 있습니다. DwmGetWindowAttribute() 및 DwmGetColorizationColor() 의 문서를 참조하십시오. 데모 응용 프로그램은 여전히 주요 창이 FramelessWidget 또는 FramelessMainWindow 에서 상속되기 때문에 여전히 최상위 경계를 가지고 있습니다. QT Quick의 경우 QML 유형 FramelessWindow 도 상단 테두리를 그립니다.
When running on Wayland, dragging the title bar causes crash? Wayland에서 실행할 때 QT가 XCB QPA를 사용하도록 강요해야합니다. Q(Gui)Application 인스턴스를 인스턴스화하기 전에 환경 변수 QT_QPA_PLATFORM (CASE CINTITITION)을 xcb (Case Cintitive)로 설정하십시오. 또는 void FramelessHelper::Widgets/Quick::initialize() main 함수에서 호출하면이 기능이 처리됩니다.
I can see the black background during window resizing?우선, 그것은 FramelessHelper에 의해 발생하는 QT 문제입니다. QT 위젯 애플리케이션에는 가능하지 않아야합니다. QT Quick Applications의 일반적인 문제입니다. 대부분의 경우 D3D11/Vulkan/Metal에 의해 발생합니다. 텍스처 크기 조정 작업을 잘 처리하지 않기 때문입니다. 이 문제를 실제로 해결하려면 QT의 RHI 백엔드를 OpenGL (그래픽 카드 드라이버의 버그에주의) 또는 소프트웨어 (성능에 관심이없는 경우)로 변경하려고 시도 할 수 있습니다. 그리고이 문제는 QT 외부에서 고칠 수 없음을 명심하십시오.
Can I preserve the window frame border even on Win7? How does Google Chrome/Microsoft Edge's installer achieve that? 짧은 대답 : 불가능합니다. 전체 설명 : 물론 Win10에서 사용하는 것과 동일한 기술을 사용하여 창의 전체 상단 부분을 제거하고 동시에 다른 세 프레임 경계를 보존 할 수 있지만 Win10에서는 WM_PAINT 핸들러에서 약간의 검은 마법을 수행하거나 수동으로 얇은 프레임 테두리를 그릴 수 있지만 Win7에서는 불가능합니다. 나는 이미 Win7에서 시도해 보았고 슬프게도 결과는 WM_PAINT 트릭이 Win7에서 작동하지 않을 것이며, 원래의 것과 매우 유사한 프레임 테두리 (Semi-Transparent 사각형, 시스템의 악센트 색상 및 창 뒤의 시각적 콘텐츠, 또한 일부 흐림 효과가 적용됨)를 그릴 수는 없습니다. 그러나 Google Chrome/Microsoft Edge의 설치 프로그램이 우리가하고 싶은 일을 어떻게 달성 한 것 같습니다. 글쎄, 그들의 설치 프로그램은 오픈 소스이며 이미 코드를 읽었습니다. 그들은 두 개의 창, 하단에 하나의 일반 창, 상단의 다른 경계가없는 창을 겹쳐서 바닥 창의 제목 표시 줄을 덮어서이를 달성합니다. 그들은 수제 타이틀 바를 국경없는 창에 그려 표준 타이틀 바의 행동을 모방하는 데 사용합니다. 시스템이 제공하는 원래 제목 표시 줄은 여전히 존재하지만 다른 창으로 덮여 있기 때문에 누구에게도 볼 수 없습니다. 나는 그것이 그러한 경우에 좋은 솔루션이라는 것을 인정하지만 우리 도서관의 경우 코드 복잡성이 폭발하기 때문에 적절하지 않습니다.
첫 번째 기부 시간에 따라 주문 (정확하지 않을 수 있습니다. 죄송합니다)
MIT License
Copyright (C) 2021-2023 by wangwenx190 (Yuhang Zhao)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.