
إطار تخصيص النوافذ عبر المنصات للأغذية QT و QT Quick. يدعم Windows و Linux و MacOS.
يمكنك الانضمام إلى قناة Discord الخاصة بنا للتواصل معنا. يمكنك مشاركة النتائج التي توصلت إليها وأفكارك وأفكارك حول تحسين / تنفيذ وظائف الإطار على المزيد من المنصات والتطبيقات!
FramelessDialog . يمكنك استخدامه في حالة تفضيل QDialog على QWidget عام.WindowBorderPainter التي تم تقديمها حديثًا ، كما أنها تعرض علنًا ، لذلك ستتمكن من تغيير كيفية رسم حدود النافذة بسهولة.WindowBorder . إنه ديكور حدود النافذة عبر المنصات ، ويمكنه العمل بدون عنصر FramelessHelper .FramelessApplicationWindow . إنه غلاف بسيط لعنصر ApplicationWindow القياسي ، فقط يزيل شريط العنوان ويضيف حدود النافذة.find_package للعثور على FramelessHelper.






محرر Vogen باستخدام Framework QSynthesis . url 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 . على سبيل المثال: -DCMAKE_PREFIX_PATH=C:/my-cmake-packages;C:/my-toolchain;etc... أو -DFramelessHelper_DIR=C:/Projects/FramelessHelper/lib64/cmake/FramelessHelper . بناء ، بناء ، كدليل فرعي لمشروع CMAKE الخاص بك ، بالطبع مدعوم أيضًا. الأسماء المستهدفة المدعومة من الإطار هي 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 بعمل كل عمل باقي من أجلك: سيتم إزالة إطار النافذة تلقائيًا بمجرد إرفاقه بمستوى أعلى مستوي. من الناحية النظرية ، يمكنك إنشاء كائنات متعددة FramelessWidgetsHelper لنفس عنصر واجهة مستخدم ، في هذه الحالة سيكون هناك كائن واحد فقط يحافظ على وظيفية ، ستصبح جميع الكائنات الأخرى غلافًا لذلك. ولكن للتأكد من أن كل شيء يسير بسلاسة وعادة ، يجب ألا تفعل ذلك في أي حال. إن أبسط طريقة لتشكيل كائن FramelessWidgetsHelper هي استدعاء الطريقة الثابتة FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *) . سيعود مقبض الكائن الذي تم إنشاءه مسبقًا إن وجد ، أو أنه سيؤدي إلى إنشاء كائن جديد إذا لم يتمكن من العثور على واحد. من الآمن استدعاء هذه الطريقة عدة مرات لنفس عنصر واجهة المستخدم ، فلن تقوم بتثبيت أي كائنات جديدة إذا كان هناك طريقة بالفعل. كما أنه لا يهم متى وأين تسمي هذه الوظيفة طالما أن عنصر القطعة العليا هو نفسه. سيتم دائمًا الوالدين الكائنات التي تم إنشاؤها داخليًا إلى عنصر واجهة المستخدم ذات المستوى الأعلى. بمجرد حصولك على مقبض كائن FramelessWidgetsHelper ، يمكنك استدعاء void FramelessWidgetsHelper::extendsContentIntoTitleBar() للسماح لها بإخفاء شريط العنوان الافتراضي الذي يوفره نظام التشغيل. من أجل التأكد من أن FramelessWidgetsHelper يمكن أن تجد عنصر واجهة مستوية صحيحة صحيحة ، يجب عليك استدعاء وظيفة FramelessWidgetsHelper *FramelessWidgetsHelper::get(QObject *) على عنصر واجهة مستخدم يحتوي على سلسلة من الوالدين الكاملة التي يكون الوالد الجذري هي المصحيحية ذات المستوى الأعلى. لجعل نافذة الإطار قابلة للسحب ، يجب عليك توفير عنصر واجهة مستخدم محلية الصنع بنفسك ، لا يلزم أن يكون عنصر عنصر شريط العنوان في شكل مستطيل ، كما أنه لا يلزم وضعه في الصف الأول من النافذة. Call void FramelessWidgetsHelper::setTitleBarWidget(QWidget *) للسماح لـ FramelessHelper بمعرفة عنصر اللقب الخاص بك. بشكل افتراضي ، لن تكون جميع الأدوات المصغّرة في منطقة شريط العنوان مسؤولة عن أي أحداث الماوس ولوحة المفاتيح بسبب اعتراضها بواسطة FramelessHelper. لجعلهم يستعدون الحالة المسؤولة ، يجب أن تجعلها مرئية لضرب الاختبار. استدعاء void FramelessWidgetsHelper::setHitTestVisible(QWidget* ) للقيام بذلك. يمكنك بالطبع تسميته على عنصر واجهة مستخدم لا يوجد داخل شريط العنوان على الإطلاق ، لن يكون له أي تأثير. نظرًا لقيود QT الخاصة ، تحتاج إلى التأكد من أن القطعة الخاصة بك لديها سلسلة من الوالدين الكاملة التي يكون الوالد الجذري هو عنصر واجهة المستخدم من المستوى الأعلى. لا تحاول أبدًا حذف كائن FramelessWidgetsHelper ، فقد لا يزال يراقب ويتحكم في عنصر واجهة المستخدم ، وسيقوم QT بحذفه لك تلقائيًا. لا داعي للقلق بشأن تسرب الذاكرة.
هناك أيضًا فئتان تسمى FramelessWidget و FramelessMainWindow ، وهما فقط مغلفة بسيطة من FramelessWidgetsHelper ، والتي تحفظ فقط دعوة void FramelessWidgetsHelper::extendsContentIntoTitleBar() بالنسبة لك. يمكنك استخدام QWidget عادي بدلاً من ذلك.
بادئ ذي بدء ، استدعاء void FramelessHelper::Widgets::initialize() في وظيفتك main في مرحلة مبكرة للغاية ( يجب قبل بناء أي كائنات Q(Gui|Core)Application ):
int main ( int , char **)
{
FramelessHelper::Widgets::initialize ();
// ...
}ثم إخفاء شريط العنوان القياسي الذي يوفره نظام التشغيل:
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 من عملية تخصيص النوافذ ، مثل تغيير هندسة النوافذ/الأعلام/الحالة. في هذه الحالة ، يمكنك الاتصال بإشارة Public void ready() لـ FramelessHelper للحصول على نقطة زمنية دقيقة والقيام بعملية تهيئة الراحة بعد ذلك.
بادئ ذي بدء ، يجب أن تسمي void FramelessHelper::Quick::initialize() في وظيفتك main في مرحلة مبكرة جدًا ( يجب قبل بناء أي كائنات Q(Gui|Core)Application ):
int main ( int , char **)
{
FramelessHelper::Quick::initialize ();
// ...
} ثم تحتاج إلى تسجيل الأنواع المخصصة التي يوفرها FramelessHelper عن طريق استدعاء void FramelessHelper::Quick::registerTypes(QQmlEngine *) ، قبل أن يقوم محرك QML بتحميل أي مستندات QML:
int main ( int , char **)
{
// ...
QQmlApplicationEngine engine;
FramelessHelper::Quick::registerTypes (&engine);
// ...
} الآن يمكنك كتابة مستندات QML الخاصة بك. يجب عليك استيراد FramelessHelper من uri org.wangwenx190.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
}
} من الناحية النظرية ، من الممكن إنشاء كائنات متعددة FramelessHelper لنفس Window ، وفي هذه الحالة ، سيحافظ واحد منها فقط على وظيفية ، ستصبح جميع الكائنات الأخرى غلافًا لها ، لكن القيام بذلك لا ينصح به وقد يتسبب في سلوك غير متوقع أو أخطاء ، لذا يرجى تجنب محاولة القيام بذلك في أي حال.
إذا وجدت أيًا من وظائف FramelessHelper ليس لها أي تأثير بعد الاتصال ، فإن السبب الأكثر إمكانية هو الوقت الذي تتصل فيه بالوظيفة/تغيير خاصية FramelessHelper ، لم تنته نافذة الجذر عملية التهيئة ، وبالتالي لا يمكن أن يحصل على FramelessHelper ، لذلك سيتم تجاهل أي إجراء من المستخدم حتى تهيئة النافذة الجذرية.
هناك أيضًا نوع QML يسمى FramelessWindow ، إنه مجرد غلاف بسيط من FramelessHelper ، يمكنك استخدام Window عادي بدلاً من ذلك.
ملاحظة مهمة للتطبيقات السريعة QT : قد تكون بعض الوظائف متاحة فقط عندما تنتهي FramelessHelper من عملية تخصيص النوافذ ، مثل تغيير هندسة النوافذ/الأعلام/الحالة. في هذه الحالة ، يمكنك الاتصال بإشارة void ready() لـ FramelessHelper للحصول على نقطة زمنية دقيقة والقيام بعملية تهيئة الراحة بعد ذلك:
Window {
FramelessHelper . onReady : {
// do something here ...
}
} Window {
FramelessHelper {
onReady : {
// do something here ...
}
}
}يرجى الرجوع إلى المشاريع التجريبية لمشاهدة استخدامات أكثر تفصيلاً: أمثلة
إذا تم تعطيل تكوين DWM في بعض الحالات النادرة جدًا (ممكن فقط على Windows 7) ، فستظهر الزاوية العلوية اليسرى والركن العلوي الأيمن في شكل دائري. يمكن استعادة الزوايا المستديرة إلى مربع إذا قمت بإعادة تمكين تكوين DWM.
هناك خطأ في برنامج تشغيل OpenGL والذي سيؤدي إلى بعض النوافذ التي لا تتبعها شريط أسود غريب مباشرة أعلى شريط العنوان محلي الصنع ، كما أنه يجعل عناصر التحكم في النوافذ الخاصة بك تحولت إلى الزاوية اليمنى السفلية لبعض وحدات البكسل. إنه خطأ من برنامج تشغيل بطاقة الرسومات الخاصة بك ، وتحديداً برنامج تشغيل OpenGL الخاص بك ، وليس بدون إطار. هناك بعض الحلول التي يقدمها مستخدمونا ولكن بعضهم قد لا يعمل في جميع الظروف ، يمكنك اختيار واحد منهم:
| حل | مبدأ |
|---|---|
| ترقية برنامج تشغيل الرسومات | حاول استخدام برنامج تشغيل أحدث قد يشحن مع الإصلاح |
| قم بتغيير موضوع النظام إلى "أساسي" (على عكس "Windows Aero") | دع Windows يستخدم عرض البرامج الخالصة |
| إذا كانت هناك بطاقات رسومات متعددة ، فاستخدم ورقة أخرى بدلاً من ذلك | حاول استخدام برنامج تشغيل مختلف قد لا يكون له مثل هذا الخطأ على الإطلاق |
| قم بترقية النظام إلى Windows 11 على الأقل | أعيد تصميم نظام التشغيل Windows 11 حتى لا يمكن تشغيل الخطأ |
قم بإزالة الأنماط WS_THICKFRAME وأنماط WS_OVERLAPPED من النافذة ، وربما أيضًا إضافة نمط WS_POPUP في نفس الوقت ، ولا تفعل أي شيء داخل كتلة WM_NCCALCSIZE (فقط أعد false مباشرة أو إزالة/التعليق على الكتلة بأكملها) | حاول أن تعكس سلوك QT FramelessWindowHint |
استخدم Qt::FramelessWindowHint بدلاً من القيام بخدعة WM_NCCALCSIZE | يختلف مسار رمز عرض QT تمامًا بين هذين الحلين |
| إجبار QT على استخدام الواجهة الخلفية للزاوية بدلاً من سطح المكتب OpenGL | ستقوم الزاوية بترجمة توجيهات OpenGL إلى تلك D3D |
| إجبار QT على استخدام عرض البرامج الخالصة بدلاً من تقديمه عبر OpenGL | QT لا يستخدم OpenGL على الإطلاق |
| إجبار QT على استخدام مكتبات MESA 3D بدلاً من OpenGL العادية | حاول استخدام تطبيق OpenGL مختلف |
| استخدم Direct3D/Vulkan/Metal بدلاً من OpenGL | فقط لا تستخدم عربات التي تجرها الدواب |
إذا كنت محظوظًا بما فيه الكفاية ، فقد يقوم أحدهم بإصلاح المشكلة لك. إذا لم يكن الأمر كذلك ، فقد تحاول استخدام حلول متعددة معًا. لكن لا يمكنني ضمان إصلاح المشكلة بنسبة 100 ٪.
نظرًا لوجود العديد من العوامل الفرعية لنظام التشغيل Windows 10 ، يوصى بشدة باستخدام أحدث إصدار من Windows 10 ، على الأقل أكبر من Windows 10 1809 . إذا حاولت استخدام هذا الإطار على بعض إصدارات Windows 10 القديمة جدًا مثل 1507 أو 1607 ، فقد تكون هناك بعض مشكلات التوافق. استخدام هذا الإطار على Windows 7 مدعوم أيضًا ولكن لا ينصح به. للحصول على السلوك الأكثر استقرارًا وأفضل مظهر ، يجب عليك استخدامه في أحدث إصدار من Windows 10 أو Windows 11.
لجعل التخطيط المفاجئ يعمل كما هو متوقع ، هناك بعض القواعد الإضافية لأزرار النظام محلية الصنع لمتابعة:
setSystemButton() لكل زر (يمكن أن يكون أي QWidget أو Qquickitem ) للسماح لزر الإطار بدون إطار وهو زر الحد الأدنى/الإغلاق إلى الحد الأقصى.When running on Win10, it seems the top border is missing? But the demo applications still have it? يخفي FramelessHelper شريط عنوان النظام عن طريق إزالة الجزء العلوي بالكامل من إطار النافذة ، بما في ذلك الحدود العلوية. لا توجد وسيلة لإزالة شريط عنوان النظام فقط ولكن لا يزال يحافظ على الحدود العلوية في نفس الوقت ، حتى Microsoft Profelds Sself لا يمكنهم فعل ذلك أيضًا. السبب الدقيق غير معروف للمطورين غير الميكروسوف ، وليس لدي أي مصلحة في البحث في كل السحر وراءه. لذلك عليك أن ترسم نفسك يدويًا للتظاهر بأن الحدود العلوية لا تزال موجودة. يمكنك استرداد الطول واللون من خلال واجهات برمجة تطبيقات DWM الرسمية. يرجى الرجوع إلى وثائق DwmGetWindowAttribute() و DwmGetColorizationColor() . لا يزال لدى التطبيقات التجريبية الحدود العليا لأن نوافذها الرئيسية جميعها ترث من FramelessWidget أو FramelessMainWindow ، والتي ستجذب الحدود العلوية لك داخليًا. أما بالنسبة لـ QT Quick ، فإن نوع QML FramelessWindow سوف يرسم أيضًا الحدود العلوية.
When running on Wayland, dragging the title bar causes crash? تحتاج إلى إجبار QT على استخدام XCB QPA عند التشغيل على Wayland. حاول تعيين متغير البيئة QT_QPA_PLATFORM (حساس الحالة) على xcb (حساس الحالة) قبل إنشاء مثيل لأي مثيلات Q(Gui)Application . أو فقط استدعاء void FramelessHelper::Widgets/Quick::initialize() في وظيفتك main ، هذه الوظيفة ستهتم بها لك.
I can see the black background during window resizing?بادئ ذي بدء ، إنها مشكلة QT ، لا تسببها الإطار. ولا ينبغي أن يكون من الممكن لتطبيقات QT Widgets. إنها مشكلة شائعة للتطبيقات السريعة QT. في معظم الأوقات ، يحدث ذلك بسبب D3D11/Vulkan/Metal لأنها ليست جيدة في التعامل مع عمليات تغيير حجم الملمس. إذا كنت ترغب حقًا في حل هذه المشكلة ، فيمكنك محاولة تغيير الواجهة الخلفية لـ QT إلى 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 Trick لن تعمل على Win7 ، كما لا يمكننا رسم حدود إطار تشبه إلى حد كبير الحدود الأصلية (مستطيل شبه شفاف ، ممزوج بلون لهجة النظام والمحتوى المرئي خلف النافذة ، مع بعض تأثير ضبابي). ولكن يبدو أن مثبت 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.