Files
CapCutAPI/pyJianYingDraft/jianying_ui_inspector.py

318 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import uiautomation as auto
import time
import json
from typing import Dict, List, Optional
class JianYingUIInspector:
def __init__(self):
self.jianying_window = None
def find_jianying_window(self) -> bool:
"""查找剪映窗口"""
# 尝试多种可能的窗口名称
window_names = [
"剪映",
"JianYing",
"CapCut",
"剪映专业版"
]
for name in window_names:
try:
# 按窗口标题查找
window = auto.WindowControl(searchDepth=1, Name=name)
if window.Exists(0, 0):
self.jianying_window = window
print(f"找到剪映窗口: {name}")
return True
# 按类名查找(如果知道的话)
window = auto.WindowControl(searchDepth=1, ClassName="Qt5QWindowIcon")
if window.Exists(0, 0) and name.lower() in window.Name.lower():
self.jianying_window = window
print(f"找到剪映窗口: {window.Name}")
return True
except Exception as e:
continue
# 如果按名称找不到,尝试遍历所有窗口
print("按名称未找到,正在遍历所有窗口...")
for window in auto.GetRootControl().GetChildren():
if window.ControlType == auto.ControlType.WindowControl:
window_title = window.Name
if any(keyword in window_title for keyword in ["剪映", "JianYing", "CapCut"]):
self.jianying_window = window
print(f"找到剪映窗口: {window_title}")
return True
print("未找到剪映窗口,请确保剪映正在运行")
return False
def get_control_info(self, control) -> Dict:
"""获取控件的详细信息"""
try:
info = {
"Name": control.Name,
"ControlType": control.ControlTypeName,
"ClassName": getattr(control, 'ClassName', ''),
"AutomationId": getattr(control, 'AutomationId', ''),
"BoundingRectangle": {
"left": control.BoundingRectangle.left,
"top": control.BoundingRectangle.top,
"right": control.BoundingRectangle.right,
"bottom": control.BoundingRectangle.bottom,
"width": control.BoundingRectangle.width(),
"height": control.BoundingRectangle.height()
},
"IsEnabled": control.IsEnabled,
"IsVisible": getattr(control, 'IsOffscreen', True) == False,
"ProcessId": getattr(control, 'ProcessId', 0)
}
# 获取FullDescription属性 (属性ID: 30159)
try:
if hasattr(control, 'GetCurrentPropertyValue'):
full_description = control.GetCurrentPropertyValue(30159)
info["FullDescription"] = full_description or ""
else:
info["FullDescription"] = ""
except Exception as e:
info["FullDescription"] = ""
info["FullDescriptionError"] = str(e)
# 获取文本内容的多种方式
text_content = ""
# 方式1: 通过Value属性获取
try:
if hasattr(control, 'GetValuePattern'):
value_pattern = control.GetValuePattern()
if value_pattern:
text_content = value_pattern.Value
except:
pass
# 方式2: 通过Text属性获取
try:
if hasattr(control, 'GetTextPattern'):
text_pattern = control.GetTextPattern()
if text_pattern:
text_content = text_pattern.DocumentRange.GetText(-1)
except:
pass
# 方式3: 直接通过属性获取
try:
if not text_content and hasattr(control, 'CurrentValue'):
text_content = str(control.CurrentValue)
except:
pass
# 方式4: 通过LegacyIAccessible获取
try:
if not text_content and hasattr(control, 'GetLegacyIAccessiblePattern'):
legacy_pattern = control.GetLegacyIAccessiblePattern()
if legacy_pattern:
text_content = legacy_pattern.CurrentValue or legacy_pattern.CurrentName
except:
pass
# 方式5: 对于QML控件尝试获取特定属性
try:
if not text_content and "QQuickText" in info["ClassName"]:
# QML Text控件可能需要特殊处理
if hasattr(control, 'GetCurrentPropertyValue'):
# 尝试获取Text属性
text_content = control.GetCurrentPropertyValue(auto.PropertyId.ValueValueProperty)
except:
pass
info["TextContent"] = text_content or ""
info["HasText"] = bool(text_content)
# 原有的其他属性获取
try:
info["Value"] = control.GetValuePattern().Value if hasattr(control, 'GetValuePattern') else ""
except:
info["Value"] = ""
try:
info["IsSelected"] = control.GetSelectionItemPattern().IsSelected if hasattr(control, 'GetSelectionItemPattern') else False
except:
info["IsSelected"] = False
return info
except Exception as e:
return {"Error": str(e), "Name": "获取信息失败"}
def build_ui_tree(self, control, max_depth: int = 10, current_depth: int = 0) -> Dict:
"""递归构建UI元素树"""
if current_depth >= max_depth:
return {"MaxDepthReached": True}
node = self.get_control_info(control)
node["Depth"] = current_depth
node["Children"] = []
try:
children = control.GetChildren()
for child in children:
if child.Exists(0, 0): # 检查子控件是否存在
child_node = self.build_ui_tree(child, max_depth, current_depth + 1)
node["Children"].append(child_node)
except Exception as e:
node["ChildrenError"] = str(e)
return node
def print_ui_tree(self, node: Dict, indent: str = ""):
"""打印UI树结构"""
control_type = node.get("ControlType", "Unknown")
name = node.get("Name", "")
class_name = node.get("ClassName", "")
automation_id = node.get("AutomationId", "")
full_description = node.get("FullDescription", "")
# 构建显示文本
display_parts = [control_type]
if name:
display_parts.append(f'Name="{name}"')
if class_name:
display_parts.append(f'Class="{class_name}"')
if automation_id:
display_parts.append(f'Id="{automation_id}"')
if full_description:
# 限制FullDescription显示长度避免输出过长
desc_display = full_description[:100] + "..." if len(full_description) > 100 else full_description
display_parts.append(f'FullDesc="{desc_display}"')
display_text = " ".join(display_parts)
# 添加位置信息
if "BoundingRectangle" in node:
rect = node["BoundingRectangle"]
display_text += f" [{rect['left']},{rect['top']},{rect['width']}x{rect['height']}]"
print(f"{indent}{display_text}")
# 递归打印子节点
for child in node.get("Children", []):
self.print_ui_tree(child, indent + " ")
def save_ui_tree_to_file(self, tree: Dict, filename: str = "jianying_ui_tree.json"):
"""保存UI树到文件"""
try:
with open(filename, 'w', encoding='utf-8') as f:
json.dump(tree, f, ensure_ascii=False, indent=2)
print(f"UI树已保存到: {filename}")
except Exception as e:
print(f"保存文件失败: {e}")
def find_elements_by_type(self, tree: Dict, control_type: str) -> List[Dict]:
"""按控件类型查找元素"""
results = []
if tree.get("ControlType") == control_type:
results.append(tree)
for child in tree.get("Children", []):
results.extend(self.find_elements_by_type(child, control_type))
return results
def find_elements_by_name(self, tree: Dict, name: str) -> List[Dict]:
"""按名称查找元素"""
results = []
if name.lower() in tree.get("Name", "").lower():
results.append(tree)
for child in tree.get("Children", []):
results.extend(self.find_elements_by_name(child, name))
return results
def find_text_controls(self, tree: Dict) -> List[Dict]:
"""查找所有包含文本的控件"""
results = []
if tree.get("HasText") and tree.get("TextContent"):
results.append({
"ControlType": tree.get("ControlType"),
"Name": tree.get("Name"),
"ClassName": tree.get("ClassName"),
"TextContent": tree.get("TextContent"),
"BoundingRectangle": tree.get("BoundingRectangle")
})
for child in tree.get("Children", []):
results.extend(self.find_text_controls(child))
return results
def inspect_jianying_ui(self, max_depth: int = 8, save_to_file: bool = True):
"""检查剪映UI并显示元素树"""
print("正在查找剪映窗口...")
if not self.find_jianying_window():
return None
print(f"窗口信息: {self.jianying_window.Name}")
print(f"窗口位置: {self.jianying_window.BoundingRectangle}")
print("\n正在构建UI元素树...")
# 构建UI树
ui_tree = self.build_ui_tree(self.jianying_window, max_depth)
print("\n=== 剪映UI元素树 ===")
self.print_ui_tree(ui_tree)
if save_to_file:
self.save_ui_tree_to_file(ui_tree)
return ui_tree
def list_all_windows(self):
"""列出所有窗口,帮助调试"""
print("当前所有窗口:")
for window in auto.GetRootControl().GetChildren():
if window.ControlType == auto.ControlType.WindowControl:
try:
print(f"- {window.Name} (PID: {getattr(window, 'ProcessId', 'Unknown')})")
except:
print(f"- 无法获取窗口信息")
def main():
"""主函数"""
inspector = JianYingUIInspector()
# 如果找不到剪映窗口,先列出所有窗口
if not inspector.find_jianying_window():
print("\n列出所有窗口以供参考:")
inspector.list_all_windows()
return
# 检查UI
ui_tree = inspector.inspect_jianying_ui(max_depth=6, save_to_file=True)
if ui_tree:
# 示例:查找所有按钮
buttons = inspector.find_elements_by_type(ui_tree, "ButtonControl")
print(f"\n找到 {len(buttons)} 个按钮控件")
# 示例:查找包含"导出"的元素
export_elements = inspector.find_elements_by_name(ui_tree, "导出")
if export_elements:
print(f"\n找到 {len(export_elements)} 个包含'导出'的元素:")
for elem in export_elements:
print(f" - {elem.get('ControlType')}: {elem.get('Name')}")
# 新增:查找所有包含文本的控件
text_controls = inspector.find_text_controls(ui_tree)
if text_controls:
print(f"\n找到 {len(text_controls)} 个包含文本的控件:")
for ctrl in text_controls:
print(f" - {ctrl['ControlType']}: '{ctrl['TextContent']}'")
if __name__ == "__main__":
main()