686 lines
28 KiB
Python
686 lines
28 KiB
Python
import sys
|
||
import os
|
||
import re
|
||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QLineEdit,
|
||
QComboBox, QCheckBox, QPushButton, QWidget,
|
||
QVBoxLayout, QHBoxLayout, QMessageBox, QFrame,
|
||
QTextEdit, QSlider, QProgressBar, QCalendarWidget,
|
||
QGroupBox, QRadioButton)
|
||
from PyQt5.QtCore import Qt, QUrl, QTimer, pyqtSlot
|
||
from PyQt5.QtGui import QIcon, QIntValidator, QPixmap, QImage
|
||
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
|
||
from urllib.request import urlopen
|
||
|
||
class EasyUIInterpreter:
|
||
def __init__(self):
|
||
self.app = None
|
||
self.window = None
|
||
self.widgets = {} # 存储所有组件
|
||
self.variables = {} # 存储可交互组件
|
||
self.main_layout = None
|
||
self.media_players = {} # 仅保留音频播放器
|
||
self.timers = {} # 存储定时器
|
||
self.groups = {}
|
||
|
||
def parse_and_run(self, code):
|
||
if not QApplication.instance():
|
||
self.app = QApplication(sys.argv)
|
||
else:
|
||
self.app = QApplication.instance()
|
||
|
||
# 重置UI状态
|
||
self.widgets = {}
|
||
self.variables = {}
|
||
self.media_players = {}
|
||
self.timers = {}
|
||
self.groups = {}
|
||
self.window = None
|
||
self.main_layout = None
|
||
|
||
lines = [line.strip() for line in code.split('\n') if line.strip()]
|
||
for line in lines:
|
||
self.parse_line(line)
|
||
|
||
if not self.window:
|
||
self.create_window("EUI默认窗口", 400, 300)
|
||
else:
|
||
self.main_layout.addStretch()
|
||
|
||
self.window.show()
|
||
sys.exit(self.app.exec_())
|
||
|
||
# ---------------------- 解析逻辑 ----------------------
|
||
def parse_line(self, line):
|
||
line = line.strip().rstrip(';')
|
||
if not line:
|
||
return
|
||
|
||
# 窗口配置
|
||
window_pattern = r'window\s*=\s*title="([^"]+)"\s*,\s*width=(\d+)\s*,\s*height=(\d+)(?:\s*,\s*icon="([^"]+)")?'
|
||
window_match = re.match(window_pattern, line)
|
||
if window_match:
|
||
title = window_match.group(1)
|
||
width = int(window_match.group(2))
|
||
height = int(window_match.group(3))
|
||
icon_path = window_match.group(4) if window_match.group(4) else None
|
||
self.create_window(title, width, height, icon_path)
|
||
return
|
||
|
||
# 文字标签
|
||
label_match = re.match(r'label\s*=\s*text="([^"]+)"\s*,\s*id=(\w+)', line)
|
||
if label_match:
|
||
self.create_label(label_match.group(1), label_match.group(2))
|
||
return
|
||
|
||
# 输入框
|
||
entry_pattern = r'entry\s*=\s*hint="([^"]+)"\s*,\s*id=(\w+)(?:\s*,\s*readonly=(true|false))?(?:\s*,\s*type=(number|text))?'
|
||
entry_match = re.match(entry_pattern, line)
|
||
if entry_match:
|
||
hint = entry_match.group(1)
|
||
widget_id = entry_match.group(2)
|
||
readonly = entry_match.group(3).lower() == 'true' if entry_match.group(3) else False
|
||
input_type = entry_match.group(4) if entry_match.group(4) else 'text'
|
||
self.create_entry(hint, widget_id, readonly, input_type)
|
||
return
|
||
|
||
# 下拉选择框
|
||
combo_match = re.match(r'combo\s*=\s*label="([^"]+)"\s*,\s*id=(\w+)\s*,\s*options=\[(.*?)\]', line)
|
||
if combo_match:
|
||
options = [opt.strip().strip('"') for opt in combo_match.group(3).split(',') if opt.strip()]
|
||
self.create_combobox(combo_match.group(1), combo_match.group(2), options)
|
||
return
|
||
|
||
# 多选框组
|
||
check_match = re.match(r'checkbox\s*=\s*label="([^"]+)"\s*,\s*id=(\w+)\s*,\s*options=\[(.*?)\]', line)
|
||
if check_match:
|
||
options = [opt.strip().strip('"') for opt in check_match.group(3).split(',') if opt.strip()]
|
||
self.create_checkboxes(check_match.group(1), check_match.group(2), options)
|
||
return
|
||
|
||
# 按钮
|
||
button_match = re.match(r'button\s*=\s*text="([^"]+)"\s*,\s*id=(\w+)\s*,\s*click="([^"]+)"', line)
|
||
if button_match:
|
||
self.create_button(button_match.group(1), button_match.group(2), button_match.group(3))
|
||
return
|
||
|
||
# 音频播放器
|
||
audio_pattern = r'audio\s*=\s*(url|os)="([^"]+)"\s*,\s*id=(\w+)'
|
||
audio_match = re.match(audio_pattern, line)
|
||
if audio_match:
|
||
self.create_audio_player(audio_match.group(1), audio_match.group(2), audio_match.group(3))
|
||
return
|
||
|
||
# 图片组件
|
||
image_pattern = r'image\s*=\s*(path|url|os)="([^"]+)"\s*,\s*id=(\w+)(?:\s*,\s*width=(\d+))?(?:\s*,\s*height=(\d+))?(?:\s*,\s*tooltip="([^"]+)")?'
|
||
image_match = re.match(image_pattern, line)
|
||
if image_match:
|
||
img_type = image_match.group(1)
|
||
img_path = image_match.group(2)
|
||
img_id = image_match.group(3)
|
||
width = int(image_match.group(4)) if image_match.group(4) else None
|
||
height = int(image_match.group(5)) if image_match.group(5) else None
|
||
tooltip = image_match.group(6) if image_match.group(6) else ""
|
||
self.create_image(img_type, img_path, img_id, width, height, tooltip)
|
||
return
|
||
|
||
# 滑块控件
|
||
slider_pattern = r'slider\s*=\s*label="([^"]+)"\s*,\s*id=(\w+)\s*,\s*min=(\d+)\s*,\s*max=(\d+)\s*,\s*value=(\d+)'
|
||
slider_match = re.match(slider_pattern, line)
|
||
if slider_match:
|
||
self.create_slider(
|
||
slider_match.group(1), slider_match.group(2),
|
||
int(slider_match.group(3)), int(slider_match.group(4)), int(slider_match.group(5))
|
||
)
|
||
return
|
||
|
||
# 文本区域
|
||
textarea_pattern = r'textarea\s*=\s*label="([^"]+)"\s*,\s*id=(\w+)\s*,\s*rows=(\d+)(?:\s*,\s*readonly=(true|false))?'
|
||
textarea_match = re.match(textarea_pattern, line)
|
||
if textarea_match:
|
||
readonly = textarea_match.group(4).lower() == 'true' if textarea_match.group(4) else False
|
||
self.create_textarea(textarea_match.group(1), textarea_match.group(2), int(textarea_match.group(3)), readonly)
|
||
return
|
||
|
||
# 分隔线
|
||
separator_match = re.match(r'separator\s*=\s*text="([^"]*)"\s*,\s*id=(\w+)', line)
|
||
if separator_match:
|
||
self.create_separator(separator_match.group(1), separator_match.group(2))
|
||
return
|
||
|
||
# 进度条
|
||
progress_pattern = r'progress\s*=\s*label="([^"]+)"\s*,\s*id=(\w+)\s*,\s*min=(\d+)\s*,\s*max=(\d+)\s*,\s*value=(\d+)'
|
||
progress_match = re.match(progress_pattern, line)
|
||
if progress_match:
|
||
self.create_progressbar(
|
||
progress_match.group(1), progress_match.group(2),
|
||
int(progress_match.group(3)), int(progress_match.group(4)), int(progress_match.group(5))
|
||
)
|
||
return
|
||
|
||
# 日历控件
|
||
calendar_match = re.match(r'calendar\s*=\s*label="([^"]+)"\s*,\s*id=(\w+)', line)
|
||
if calendar_match:
|
||
self.create_calendar(calendar_match.group(1), calendar_match.group(2))
|
||
return
|
||
|
||
# 单选按钮组
|
||
radio_match = re.match(r'radiogroup\s*=\s*label="([^"]+)"\s*,\s*id=(\w+)\s*,\s*options=\[(.*?)\]', line)
|
||
if radio_match:
|
||
options = [opt.strip().strip('"') for opt in radio_match.group(3).split(',') if opt.strip()]
|
||
self.create_radiogroup(radio_match.group(1), radio_match.group(2), options)
|
||
return
|
||
|
||
# 分组框
|
||
groupbox_match = re.match(r'groupbox\s*=\s*title="([^"]+)"\s*,\s*id=(\w+)', line)
|
||
if groupbox_match:
|
||
self.create_groupbox(groupbox_match.group(1), groupbox_match.group(2))
|
||
return
|
||
|
||
# 定时器
|
||
timer_pattern = r'timer\s*=\s*id=(\w+)\s*,\s*interval=(\d+)\s*,\s*action="([^"]+)"'
|
||
timer_match = re.match(timer_pattern, line)
|
||
if timer_match:
|
||
self.create_timer(timer_match.group(1), int(timer_match.group(2)), timer_match.group(3))
|
||
return
|
||
|
||
# ---------------------- 组件创建方法 ----------------------
|
||
def create_window(self, title, width, height, icon_path=None):
|
||
self.window = QMainWindow()
|
||
self.window.setWindowTitle(title)
|
||
self.window.resize(width, height)
|
||
|
||
if icon_path and os.path.exists(icon_path):
|
||
try:
|
||
self.window.setWindowIcon(QIcon(icon_path))
|
||
except Exception as e:
|
||
QMessageBox.warning(self.window, "警告", f"图标设置失败:{str(e)}")
|
||
|
||
central_widget = QWidget()
|
||
self.window.setCentralWidget(central_widget)
|
||
self.main_layout = QVBoxLayout(central_widget)
|
||
self.main_layout.setContentsMargins(20, 20, 20, 20)
|
||
self.main_layout.setSpacing(15)
|
||
|
||
def create_label(self, text, widget_id):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
label = QLabel(text)
|
||
label.setMinimumHeight(30)
|
||
self._get_current_layout().addWidget(label)
|
||
self.widgets[widget_id] = label
|
||
|
||
def create_entry(self, hint, widget_id, readonly=False, input_type='text'):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
container = QWidget()
|
||
container.setMinimumHeight(30)
|
||
layout = QHBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(10)
|
||
|
||
label = QLabel(hint)
|
||
entry = QLineEdit()
|
||
entry.setReadOnly(readonly)
|
||
if input_type == 'number':
|
||
entry.setValidator(QIntValidator())
|
||
|
||
layout.addWidget(label)
|
||
layout.addWidget(entry)
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[widget_id] = entry
|
||
self.variables[widget_id] = entry
|
||
|
||
def create_combobox(self, label_text, widget_id, options):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
container = QWidget()
|
||
container.setMinimumHeight(30)
|
||
layout = QHBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(10)
|
||
|
||
label = QLabel(label_text)
|
||
combo = QComboBox()
|
||
combo.addItems(options)
|
||
|
||
layout.addWidget(label)
|
||
layout.addWidget(combo)
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[widget_id] = combo
|
||
self.variables[widget_id] = combo
|
||
|
||
def create_checkboxes(self, label_text, widget_id, options):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
container = QWidget()
|
||
container.setMinimumHeight(60)
|
||
layout = QVBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(5)
|
||
|
||
title_label = QLabel(label_text)
|
||
layout.addWidget(title_label)
|
||
|
||
check_layout = QHBoxLayout()
|
||
check_layout.setSpacing(15)
|
||
checkboxes = []
|
||
for opt in options:
|
||
cb = QCheckBox(opt)
|
||
check_layout.addWidget(cb)
|
||
checkboxes.append(cb)
|
||
|
||
layout.addLayout(check_layout)
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[widget_id] = checkboxes
|
||
self.variables[widget_id] = checkboxes
|
||
|
||
def create_button(self, text, widget_id, action):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
button = QPushButton(text)
|
||
button.setMinimumHeight(30)
|
||
button.setMaximumWidth(150)
|
||
button.clicked.connect(lambda checked, a=action: self.handle_button_click(a))
|
||
self._get_current_layout().addWidget(button, alignment=Qt.AlignLeft)
|
||
self.widgets[widget_id] = button
|
||
|
||
def create_audio_player(self, audio_type, audio_path, audio_id):
|
||
player = QMediaPlayer()
|
||
self.media_players[audio_id] = {
|
||
"player": player,
|
||
"type": "audio"
|
||
}
|
||
|
||
try:
|
||
if audio_type == "url":
|
||
media = QMediaContent(QUrl(audio_path))
|
||
else:
|
||
abs_path = os.path.abspath(audio_path).replace(" ", "%20") # 处理空格
|
||
if not os.path.exists(abs_path.replace("%20", " ")):
|
||
QMessageBox.warning(self.window, "警告", f"音频文件不存在:{abs_path.replace('%20', ' ')}")
|
||
return
|
||
media = QMediaContent(QUrl.fromLocalFile(abs_path))
|
||
|
||
player.setMedia(media)
|
||
except Exception as e:
|
||
QMessageBox.warning(self.window, "警告", f"音频加载失败:{str(e)}")
|
||
|
||
def create_image(self, img_type, img_path, img_id, width=None, height=None, tooltip=""):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
container = QWidget()
|
||
container.setMinimumHeight(height if height else 100)
|
||
container.setMinimumWidth(width if width else 100)
|
||
layout = QVBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
|
||
img_label = QLabel()
|
||
img_label.setToolTip(tooltip)
|
||
img_label.setAlignment(Qt.AlignCenter)
|
||
|
||
pixmap = None
|
||
try:
|
||
if img_type == "path":
|
||
if img_path.startswith(('http://', 'https://')):
|
||
with urlopen(img_path) as response:
|
||
img_data = response.read()
|
||
image = QImage.fromData(img_data)
|
||
pixmap = QPixmap.fromImage(image)
|
||
else:
|
||
abs_path = os.path.abspath(img_path)
|
||
if os.path.exists(abs_path):
|
||
pixmap = QPixmap(abs_path)
|
||
else:
|
||
img_label.setText("图片文件不存在")
|
||
QMessageBox.warning(self.window, "警告", f"本地图片路径不存在:{abs_path}")
|
||
|
||
elif img_type == "url":
|
||
with urlopen(img_path) as response:
|
||
img_data = response.read()
|
||
image = QImage.fromData(img_data)
|
||
pixmap = QPixmap.fromImage(image)
|
||
|
||
elif img_type == "os":
|
||
abs_path = os.path.abspath(img_path)
|
||
if os.path.exists(abs_path):
|
||
pixmap = QPixmap(abs_path)
|
||
else:
|
||
img_label.setText("图片文件不存在")
|
||
QMessageBox.warning(self.window, "警告", f"本地图片路径不存在:{abs_path}")
|
||
|
||
except Exception as e:
|
||
img_label.setText("图片加载失败")
|
||
QMessageBox.warning(self.window, "警告", f"图片加载失败:{str(e)}")
|
||
|
||
if pixmap and not pixmap.isNull():
|
||
if width and height:
|
||
pixmap = pixmap.scaled(width, height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||
elif width:
|
||
pixmap = pixmap.scaledToWidth(width, Qt.SmoothTransformation)
|
||
elif height:
|
||
pixmap = pixmap.scaledToHeight(height, Qt.SmoothTransformation)
|
||
|
||
img_label.setPixmap(pixmap)
|
||
|
||
layout.addWidget(img_label)
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[img_id] = img_label
|
||
self.variables[img_id] = img_label
|
||
|
||
def create_slider(self, label_text, widget_id, min_val, max_val, value):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
container = QWidget()
|
||
container.setMinimumHeight(60)
|
||
layout = QVBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(5)
|
||
|
||
value_label = QLabel(f"{label_text}:{value}")
|
||
slider = QSlider(Qt.Horizontal)
|
||
slider.setRange(min_val, max_val)
|
||
slider.setValue(value)
|
||
slider.setTickInterval(1)
|
||
slider.setTickPosition(QSlider.TicksBelow)
|
||
slider.valueChanged.connect(lambda v: value_label.setText(f"{label_text}:{v}"))
|
||
|
||
layout.addWidget(value_label)
|
||
layout.addWidget(slider)
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[widget_id] = slider
|
||
self.variables[widget_id] = slider
|
||
|
||
def create_textarea(self, label_text, widget_id, rows, readonly=False):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
container = QWidget()
|
||
layout = QVBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(5)
|
||
|
||
label = QLabel(label_text)
|
||
textarea = QTextEdit()
|
||
textarea.setReadOnly(readonly)
|
||
textarea.setMinimumHeight(rows * 25)
|
||
|
||
layout.addWidget(label)
|
||
layout.addWidget(textarea)
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[widget_id] = textarea
|
||
self.variables[widget_id] = textarea
|
||
|
||
def create_separator(self, text, widget_id):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
if text:
|
||
container = QWidget()
|
||
layout = QHBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(10)
|
||
|
||
left_line = QFrame()
|
||
left_line.setFrameShape(QFrame.HLine)
|
||
left_line.setFrameShadow(QFrame.Sunken)
|
||
|
||
right_line = QFrame()
|
||
right_line.setFrameShape(QFrame.HLine)
|
||
right_line.setFrameShadow(QFrame.Sunken)
|
||
|
||
label = QLabel(text)
|
||
layout.addWidget(left_line, 1)
|
||
layout.addWidget(label, 0, Qt.AlignCenter)
|
||
layout.addWidget(right_line, 1)
|
||
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[widget_id] = container
|
||
else:
|
||
line = QFrame()
|
||
line.setFrameShape(QFrame.HLine)
|
||
line.setFrameShadow(QFrame.Sunken)
|
||
self._get_current_layout().addWidget(line)
|
||
self.widgets[widget_id] = line
|
||
|
||
def create_progressbar(self, label_text, widget_id, min_val, max_val, value):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
container = QWidget()
|
||
container.setMinimumHeight(50)
|
||
layout = QVBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(5)
|
||
|
||
label = QLabel(label_text)
|
||
progress = QProgressBar()
|
||
progress.setRange(min_val, max_val)
|
||
progress.setValue(value)
|
||
progress.setTextVisible(True)
|
||
|
||
layout.addWidget(label)
|
||
layout.addWidget(progress)
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[widget_id] = progress
|
||
self.variables[widget_id] = progress
|
||
|
||
def create_calendar(self, label_text, widget_id):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
container = QWidget()
|
||
layout = QVBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(10)
|
||
|
||
label = QLabel(label_text)
|
||
calendar = QCalendarWidget()
|
||
calendar.setSelectionMode(QCalendarWidget.SingleSelection)
|
||
|
||
layout.addWidget(label)
|
||
layout.addWidget(calendar)
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[widget_id] = calendar
|
||
self.variables[widget_id] = calendar
|
||
|
||
def create_radiogroup(self, label_text, widget_id, options):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
container = QWidget()
|
||
layout = QVBoxLayout(container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(5)
|
||
|
||
title_label = QLabel(label_text)
|
||
layout.addWidget(title_label)
|
||
|
||
radio_buttons = []
|
||
for i, opt in enumerate(options):
|
||
radio = QRadioButton(opt)
|
||
if i == 0:
|
||
radio.setChecked(True)
|
||
layout.addWidget(radio)
|
||
radio_buttons.append(radio)
|
||
|
||
self._get_current_layout().addWidget(container)
|
||
self.widgets[widget_id] = radio_buttons
|
||
self.variables[widget_id] = radio_buttons
|
||
|
||
def create_groupbox(self, title, group_id):
|
||
if not self.window:
|
||
self.create_window("默认窗口", 400, 300)
|
||
|
||
groupbox = QGroupBox(title)
|
||
group_layout = QVBoxLayout(groupbox)
|
||
group_layout.setContentsMargins(15, 15, 15, 15)
|
||
group_layout.setSpacing(10)
|
||
|
||
self._get_current_layout().addWidget(groupbox)
|
||
self.groups[group_id] = group_layout
|
||
self.widgets[group_id] = groupbox
|
||
|
||
def create_timer(self, timer_id, interval, action):
|
||
if timer_id in self.timers:
|
||
self.timers[timer_id]['timer'].stop()
|
||
|
||
timer = QTimer()
|
||
timer.setInterval(interval)
|
||
timer.timeout.connect(lambda: self.handle_timer_timeout(timer_id))
|
||
self.timers[timer_id] = {
|
||
'timer': timer,
|
||
'action': action
|
||
}
|
||
|
||
# ---------------------- 事件处理 ----------------------
|
||
def _get_current_layout(self):
|
||
return list(self.groups.values())[-1] if self.groups else self.main_layout
|
||
|
||
@pyqtSlot()
|
||
def handle_timer_timeout(self, timer_id):
|
||
if timer_id not in self.timers:
|
||
return
|
||
|
||
timer_info = self.timers[timer_id]
|
||
action = timer_info['action']
|
||
|
||
if action.startswith("update_progress="):
|
||
try:
|
||
progress_part, step_part = action.split(",")
|
||
progress_id = progress_part.split("=")[1].strip()
|
||
step = int(step_part.split("=")[1].strip())
|
||
|
||
progress_bar = self.widgets.get(progress_id)
|
||
if not progress_bar or not isinstance(progress_bar, QProgressBar):
|
||
return
|
||
|
||
current_value = progress_bar.value()
|
||
new_value = current_value + step
|
||
new_value = max(progress_bar.minimum(), min(progress_bar.maximum(), new_value))
|
||
progress_bar.setValue(new_value)
|
||
|
||
if new_value >= progress_bar.maximum():
|
||
timer_info['timer'].stop()
|
||
|
||
except Exception as e:
|
||
QMessageBox.warning(self.window, "定时器错误", f"更新进度条失败:{str(e)}")
|
||
|
||
def handle_button_click(self, action):
|
||
# 音频控制
|
||
if action.startswith("play_audio="):
|
||
self._control_audio(action.split("=")[1], "play")
|
||
return
|
||
if action.startswith("pause_audio="):
|
||
self._control_audio(action.split("=")[1], "pause")
|
||
return
|
||
if action.startswith("stop_audio="):
|
||
self._control_audio(action.split("=")[1], "stop")
|
||
return
|
||
|
||
# 定时器控制
|
||
if action.startswith("start_timer="):
|
||
timer_id = action.split("=")[1].strip()
|
||
self._control_timer(timer_id, "start")
|
||
return
|
||
if action.startswith("stop_timer="):
|
||
timer_id = action.split("=")[1].strip()
|
||
self._control_timer(timer_id, "stop")
|
||
return
|
||
|
||
# 进度条控制
|
||
if action.startswith("set_progress="):
|
||
parts = action.split(",")
|
||
if len(parts) >= 2 and parts[1].startswith("value="):
|
||
try:
|
||
p_id = parts[0].split("=")[1].strip()
|
||
val = int(parts[1].split("=")[1].strip())
|
||
if p_id in self.widgets and isinstance(self.widgets[p_id], QProgressBar):
|
||
self.widgets[p_id].setValue(val)
|
||
except Exception as e:
|
||
QMessageBox.warning(self.window, "错误", f"设置进度条失败:{str(e)}")
|
||
return
|
||
|
||
# 显示组件值
|
||
if action.startswith("显示="):
|
||
self._show_widget_value(action.split("=")[1].strip())
|
||
return
|
||
|
||
def _control_audio(self, audio_id, action):
|
||
if audio_id not in self.media_players or self.media_players[audio_id]["type"] != "audio":
|
||
QMessageBox.warning(self.window, "警告", f"音频组件ID不存在:{audio_id}")
|
||
return
|
||
player = self.media_players[audio_id]["player"]
|
||
if action == "play":
|
||
player.play()
|
||
elif action == "pause":
|
||
player.pause()
|
||
elif action == "stop":
|
||
player.stop()
|
||
|
||
def _control_timer(self, timer_id, action):
|
||
if timer_id not in self.timers:
|
||
QMessageBox.warning(self.window, "警告", f"定时器ID不存在:{timer_id}")
|
||
return
|
||
timer = self.timers[timer_id]['timer']
|
||
if action == "start":
|
||
timer.start()
|
||
elif action == "stop":
|
||
timer.stop()
|
||
|
||
def _show_widget_value(self, widget_id):
|
||
if widget_id not in self.variables:
|
||
QMessageBox.warning(self.window, "警告", f"组件ID不存在:{widget_id}")
|
||
return
|
||
|
||
target = self.variables[widget_id]
|
||
msg = ""
|
||
|
||
if isinstance(target, list) and all(isinstance(x, QCheckBox) for x in target):
|
||
selected = [cb.text() for cb in target if cb.isChecked()]
|
||
msg = f"多选框选中项:{', '.join(selected) if selected else '无'}"
|
||
elif isinstance(target, list) and all(isinstance(x, QRadioButton) for x in target):
|
||
selected = [rb.text() for rb in target if rb.isChecked()]
|
||
msg = f"单选框选中项:{', '.join(selected)}"
|
||
elif isinstance(target, QComboBox):
|
||
msg = f"下拉框选中:{target.currentText()}"
|
||
elif isinstance(target, QLineEdit):
|
||
msg = f"输入框内容:{target.text()}"
|
||
elif isinstance(target, QSlider):
|
||
msg = f"滑块值:{target.value()}"
|
||
elif isinstance(target, QTextEdit):
|
||
content = target.toPlainText()
|
||
msg = f"文本区域内容:{content[:100]}..." if len(content) > 100 else f"文本区域内容:{content}"
|
||
elif isinstance(target, QCalendarWidget):
|
||
msg = f"选中日期:{target.selectedDate().toString('yyyy-MM-dd')}"
|
||
elif isinstance(target, QProgressBar):
|
||
msg = f"进度条值:{target.value()}%"
|
||
elif isinstance(target, QLabel) and hasattr(target, 'pixmap') and target.pixmap():
|
||
msg = f"图片信息:已加载图片({target.pixmap().width()}x{target.pixmap().height()})"
|
||
|
||
QMessageBox.information(self.window, "组件值", msg)
|
||
|
||
# ---------------------- 运行入口 ----------------------
|
||
if __name__ == "__main__":
|
||
if len(sys.argv) > 1:
|
||
file_path = sys.argv[1]
|
||
try:
|
||
with open(file_path, 'r', encoding='utf-8') as f:
|
||
ewui_code = f.read()
|
||
interpreter = EasyUIInterpreter()
|
||
interpreter.parse_and_run(ewui_code)
|
||
except Exception as e:
|
||
print(f"[EUI解释器错误]:{str(e)}", file=sys.stderr)
|
||
sys.exit(1)
|
||
else:
|
||
print("=" * 50)
|
||
print("Easy UI 解释器(基础版)")
|
||
print("用法:python easy_ui.py <EWUI文件路径>")
|
||
print("支持组件:窗口、标签、按钮、输入框、下拉框、复选框等")
|
||
print("=" * 50)
|
||
sys.exit(0) |