From 392de9488aac71b3cbbae6b7d12198893802aefa Mon Sep 17 00:00:00 2001 From: HIllya51 <101191390+HIllya51@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:18:11 +0800 Subject: [PATCH 1/3] update --- ElaWidgetTools | 2 +- scripts/dobuild.py | 4 ++-- scripts/pyqt/gen_Def.sip.py | 4 ++-- scripts/pyqt/gen_widgets.py | 29 ++++++++++++++++++++++------- scripts/pyside6/gen_xml.py | 12 +++++++----- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/ElaWidgetTools b/ElaWidgetTools index aa1856b..190c02e 160000 --- a/ElaWidgetTools +++ b/ElaWidgetTools @@ -1 +1 @@ -Subproject commit aa1856b8f8589ba0a82e50c0ac01e289eb3ff2c4 +Subproject commit 190c02e5bccb3614750a986945934a77ba7d90e7 diff --git a/scripts/dobuild.py b/scripts/dobuild.py index a8836e6..48c3e79 100644 --- a/scripts/dobuild.py +++ b/scripts/dobuild.py @@ -73,7 +73,7 @@ def __parsefile(fn, cb, pr=False): lambda cml: cml.replace("add_subdirectory(ElaWidgetToolsExample)", ""), ) __parsefile( - "../ElaWidgetTools/ElaWidgetTools/ElaProperty.h", + "../ElaWidgetTools/ElaWidgetTools/ElaWidgetToolsExport.h", lambda cml: cml.replace( "Q_DECL_EXPORT", "", @@ -98,7 +98,7 @@ def __parsefile(fn, cb, pr=False): """ __parsefile( - "../ElaWidgetTools/CMakeLists.txt", + "../ElaWidgetTools/ElaWidgetTools/CMakeLists.txt", lambda c: c.replace( "add_definitions(-DELAWIDGETTOOLS_LIBRARY)", "add_definitions(-DELAWIDGETTOOLS_LIBRARY)\n" + fix, diff --git a/scripts/pyqt/gen_Def.sip.py b/scripts/pyqt/gen_Def.sip.py index 62a38d4..35582a3 100644 --- a/scripts/pyqt/gen_Def.sip.py +++ b/scripts/pyqt/gen_Def.sip.py @@ -2,7 +2,7 @@ os.chdir(os.path.dirname(os.path.abspath(__file__))) -with open("../../ElaWidgetTools/ElaWidgetTools/ElaDef.h", "r", encoding="utf8") as ff: +with open("../../ElaWidgetTools/ElaWidgetTools/ElaWidgetToolsDef.h", "r", encoding="utf8") as ff: content = ff.read() import re @@ -48,7 +48,7 @@ def parse_def_h_to_sip(header_content): sip_output.append( """ %TypeHeaderCode -#include "ElaDef.h" +#include "ElaWidgetToolsDef.h" %End """ ) diff --git a/scripts/pyqt/gen_widgets.py b/scripts/pyqt/gen_widgets.py index c47b603..d94078f 100644 --- a/scripts/pyqt/gen_widgets.py +++ b/scripts/pyqt/gen_widgets.py @@ -306,16 +306,26 @@ def generate_sip_for_class__1(header_content, filename=""): base_class_name = class_match.group(3) sip_lines.append(f"class {class_name} : public {base_class_name}\n{{") sip_lines.append("%TypeHeaderCode") - sip_lines.append(f'#include "ElaDef.h"') + sip_lines.append(f'#include "ElaWidgetToolsDef.h"') sip_lines.append(f'#include "{os.path.basename(filename)}"') sip_lines.append("%End\n") # --- Properties --- - # Q_PROPERTY_CREATE_Q_H(type, Name) - # Assumes getter: Name() or isName() for bool, Setter: setName(type) - for pt in ("Q_PROPERTY_CREATE", "Q_PROPERTY_CREATE_Q_H", "Q_PROPERTY_REF_CREATE_Q_H"): + # Q_PROPERTY_* macros declare a notify signal (pXChanged) + getter/setter. + # Q_PRIVATE_* macros declare only getter/setter (no notify signal). + PROP_MACROS = [ + ("Q_PROPERTY_CREATE", True), + ("Q_PROPERTY_CREATE_Q_H", True), + ("Q_PROPERTY_REF_CREATE_Q_H", True), + ("Q_PRIVATE_CREATE", False), + ("Q_PRIVATE_CREATE_Q_H", False), + ("Q_PRIVATE_REF_CREATE", False), + ("Q_PRIVATE_REF_CREATE_Q_H", False), + ] + has_public_section_for_props = False # To add "public:" if props are first + + for pt, has_signal in PROP_MACROS: prop_pattern = re.compile(rf"{pt}\((.*?),\s*(\w+)\)") - has_public_section_for_props = False # To add "public:" if props are first for match in prop_pattern.finditer(header_content): if not has_public_section_for_props: @@ -336,7 +346,10 @@ def generate_sip_for_class__1(header_content, filename=""): # For now, assume they follow the macro's convention # sip_lines.append(f" // Property: {prop_name}") # sip_lines.append(f" %Property({sip_prop_type} {prop_name.lower()} READ {getter_name} WRITE {setter_name})\n") - sip_lines.append(f"public: Q_SIGNAL void p{prop_name}Changed();") + if has_signal: + sip_lines.append(f"public: Q_SIGNAL void p{prop_name}Changed();") + else: + sip_lines.append("public:") sip_lines.append( f" void {setter_name}({(prop_type_raw)} {prop_name});" ) # Use input version of type @@ -573,7 +586,9 @@ def cast_h_to_sip(filename): allfiles = [] for f in os.listdir(eladir): - if f.startswith("ElaDef"): + if f.startswith("ElaWidgetToolsDef"): + continue + if f.startswith("ElaWidgetToolsExport"): continue if f.startswith("ElaProperty"): continue diff --git a/scripts/pyside6/gen_xml.py b/scripts/pyside6/gen_xml.py index f719364..97a50e6 100644 --- a/scripts/pyside6/gen_xml.py +++ b/scripts/pyside6/gen_xml.py @@ -17,13 +17,13 @@ eladir = "../../ElaWidgetTools/ElaWidgetTools" -with open(eladir + "/ElaProperty.h", "r", encoding="utf8") as ff: +with open(eladir + "/ElaPropertyMacro.h", "r", encoding="utf8") as ff: pro = ff.read() # 如果不这样改,信号会被识别成方法。 if not ("Q_SIGNALS:Q_SIGNAL" in pro): pro = re.sub(r"Q_SIGNAL(.*?)\\", r"Q_SIGNALS:Q_SIGNAL \1\\\npublic:\\", pro) - with open(eladir + "/ElaProperty.h", "w", encoding="utf8") as ff: + with open(eladir + "/ElaPropertyMacro.h", "w", encoding="utf8") as ff: ff.write(pro) @@ -143,7 +143,9 @@ def gen_widgets(eladir: str): hs = [] xmls = [] for f in os.listdir(eladir): - if f.startswith("ElaDef"): + if f.startswith("ElaWidgetToolsDef"): + continue + if f.startswith("ElaWidgetToolsExport"): continue if f.startswith("ElaProperty"): continue @@ -158,7 +160,7 @@ def gen_widgets(eladir: str): def gen_defs(): - with open(eladir + "/ElaDef.h", "r", encoding="utf8") as ff: + with open(eladir + "/ElaWidgetToolsDef.h", "r", encoding="utf8") as ff: header_content = ff.read() sip_output = [] @@ -284,7 +286,7 @@ def maybeparse(xx: str): #endif """ -H_internal = """#include """ +H_internal = """#include """ with open("wrapper.hpp", "w", encoding="utf8") as ff: ff.write(wrapperbase.format(internal=H_internal + "\n" + h)) From 1e70801447a9348c7ccbb2a52fdedff6ea3d7ada Mon Sep 17 00:00:00 2001 From: HIllya51 <101191390+HIllya51@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:40:21 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix(gen=5Fwidgets):=20=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E5=AE=8F=E5=8F=AA=E6=89=AB=E6=8F=8F=E7=B1=BB=E4=BD=93=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E5=B5=8C=E5=A5=97=E7=BB=93=E6=9E=84=E4=BD=93?= =?UTF-8?q?=E7=9A=84=E8=AE=BF=E9=97=AE=E5=99=A8=E8=AF=AF=E5=BD=92=E5=88=B0?= =?UTF-8?q?=E7=B1=BB=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ElaSuggestBox 的 SuggestData 嵌套结构体用了 Q_PRIVATE_* 宏, 属性循环原来扫整个头文件,导致 setElaIcon/getElaIcon 等被生成到 ElaSuggestBox 类上(C++ 不存在这些方法),链接失败。 改为只扫描 class { ... }; 类体。 Co-Authored-By: Claude --- scripts/pyqt/gen_widgets.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/pyqt/gen_widgets.py b/scripts/pyqt/gen_widgets.py index d94078f..f490dab 100644 --- a/scripts/pyqt/gen_widgets.py +++ b/scripts/pyqt/gen_widgets.py @@ -313,6 +313,16 @@ def generate_sip_for_class__1(header_content, filename=""): # --- Properties --- # Q_PROPERTY_* macros declare a notify signal (pXChanged) + getter/setter. # Q_PRIVATE_* macros declare only getter/setter (no notify signal). + # Only scan the class body: property macros that belong to other types in the + # same header (e.g. ElaSuggestBox's nested SuggestData struct) must not be + # attributed to this class, or sip will generate accessors that don't exist. + _class_body_for_props = re.search( + r"class\s+ELA_EXPORT\s+\w+\s*:\s*public\s+\w+\s*\{(.*?)(\};)", + header_content, + re.DOTALL, + ) + prop_scan = _class_body_for_props.group(1) if _class_body_for_props else header_content + PROP_MACROS = [ ("Q_PROPERTY_CREATE", True), ("Q_PROPERTY_CREATE_Q_H", True), @@ -327,7 +337,7 @@ def generate_sip_for_class__1(header_content, filename=""): for pt, has_signal in PROP_MACROS: prop_pattern = re.compile(rf"{pt}\((.*?),\s*(\w+)\)") - for match in prop_pattern.finditer(header_content): + for match in prop_pattern.finditer(prop_scan): if not has_public_section_for_props: # Properties are usually public in SIP even if members are private # sip_lines.append("public:") # Not strictly needed for %Property From d7d8adf3e28b2fbb18f7bf61f228fbffdfbf7fc1 Mon Sep 17 00:00:00 2001 From: HIllya51 <101191390+HIllya51@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:53:55 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix(dobuild):=20VS2026=20=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E5=9D=97=E5=8E=BB=E6=8E=89=20=5FHAS=5FCXX20=3D1=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=20requires=20=E7=BC=96=E8=AF=91=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _HAS_CXX20=1 与 /std:c++17 矛盾:前者强制 type_traits 走 C++20 路径(用 requires),后者下编译器不认 requires 关键字,导致 error C2061。该 fix 块上次被改为真正注入后此矛盾暴露。 去掉该 define,保持一致的 C++17。 Co-Authored-By: Claude --- scripts/dobuild.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/dobuild.py b/scripts/dobuild.py index 48c3e79..8e6aa26 100644 --- a/scripts/dobuild.py +++ b/scripts/dobuild.py @@ -90,7 +90,6 @@ def __parsefile(fn, cb, pr=False): add_compile_definitions( _SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS _HAS_CXX17=1 - _HAS_CXX20=1 _CRT_SECURE_NO_WARNINGS ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17 /Zc:__cplusplus")