from PySide6.QtWidgets import (QApplication, QWidget, QPushButton, QLabel, QVBoxLayout, QHBoxLayout) from PySide6.QtGui import QPainter, QColor, QFont, QPixmap, Qt, QBrush from PySide6.QtCore import QPoint, Signal, Slot import sys # 圆形按钮 from .circular_button import CircularButton from .clamp_widget import ClampWidget import resources.resources_rc class HopperWidget(QWidget): # 上料斗破拱信号 # 开启破拱 True,关闭破拱 False upper_arch_breaking_signal = Signal(bool) # 下料斗破拱信号 # 开启破拱 True,关闭破拱 False lower_arch_breaking_signal = Signal(bool) def __init__(self): super().__init__() self.setWindowTitle("料斗控制界面") # 破拱状态 (True/False) self.upper_arch_breaking_status = False # 初始为不破拱状态 self.lower_arch_breaking_status = False # 初始为不破拱状态 # 料斗控制界面的固定大小为 332x482, # 需要根据具体的料斗的图片来调整 # self.setFixedSize(356, 496) self.setFixedSize(356, 516) # 创建上位和下位料斗 self.upper_hopper = self.create_upper_hopper() self.lower_hopper = self.create_lower_hopper() # 主布局 main_layout = QVBoxLayout(self) main_layout.addWidget(self.upper_hopper) main_layout.addWidget(self.lower_hopper) main_layout.setSpacing(0) main_layout.setContentsMargins(10, 10, 0, 10) self.connectSignalToSlot() def create_upper_hopper(self): """创建上位料斗Widget""" group = QWidget() # 上位的 料斗控件的固定尺寸 !!!! # 注意: 这里需要根据具体的料斗图片来修改 # group.setFixedSize(332, 202) group.setFixedSize(332, 222) # 调整!! # group.setStyleSheet("background-color: green") layout = QVBoxLayout(group) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) # 标题标签(上位) self.upper_title_label = QLabel("上位料斗") self.upper_title_label.setFixedSize(117, 23) self.upper_title_label.setAlignment(Qt.AlignCenter) # self.upper_title_label.setStyleSheet("color: #2fd3f2; font-size: 14px; font-weight: bold;") # self.upper_title_label.setStyleSheet("color: #0bffff; font-size: 18px;") self.upper_title_label.setStyleSheet(""" color: #0bffff; font-size: 18px; background-image: url(:/icons/images/文字标题底.png); background-repeat: no-repeat; background-position: center; margin-bottom: 4px; """) layout.addWidget(self.upper_title_label, alignment=Qt.AlignCenter) # 加载外框图片 outer_img = ":/icons/images/料斗1.png" outer_pixmap = QPixmap(outer_img) if outer_pixmap.isNull(): print(f"警告:图片 {outer_img} 加载失败,请检查路径!") return group outer_width = outer_pixmap.width() outer_height = outer_pixmap.height() # 背景容器(上位) self.upper_bg_widget = QWidget() self.upper_bg_widget.setFixedSize(outer_width, outer_height) self.upper_bg_widget.setStyleSheet(f"background-image: url({outer_img}); background-repeat: no-repeat; background-position: center;") layout.addWidget(self.upper_bg_widget, alignment=Qt.AlignCenter) # 内框图片(上位) inner_img = ":/icons/images/料斗2.png" inner_pixmap = QPixmap(inner_img) if not inner_pixmap.isNull(): self.upper_inner_label = QLabel(self.upper_bg_widget) self.upper_inner_label.setPixmap(inner_pixmap) self.upper_inner_label.setFixedSize(inner_pixmap.width(), inner_pixmap.height()) self.upper_inner_label.move(14, 9) # 状态图片(上位,绿色) status_img = ":/icons/images/料斗状态绿.png" status_pixmap = QPixmap(status_img) if not status_pixmap.isNull(): status_pixmap = status_pixmap.scaled(13, 13, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.upper_status_label = QLabel(self.upper_bg_widget) self.upper_status_label.setPixmap(status_pixmap) self.upper_status_label.move(22, 12) self.upper_status_label.setScaledContents(False) self.upper_status_label.setStyleSheet("background: none;") # 破拱图片(上位) arch_img = ":/icons/images/破拱.png" arch_pixmap = QPixmap(arch_img) if not arch_pixmap.isNull(): arch_pixmap = arch_pixmap.scaled(16, 13, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.upper_arch_label = QLabel(self.upper_bg_widget) self.upper_arch_label.setPixmap(arch_pixmap) self.upper_arch_label.move(outer_width - 39, 12) self.upper_arch_label.setStyleSheet("background: none;") self.upper_arch_label.setHidden(True) # 初始,不破拱状态,隐藏 # 重量文字(上位) self.upper_weight_label = QLabel("5000kg", self.upper_bg_widget) self.upper_weight_label.setAlignment(Qt.AlignCenter) self.upper_weight_label.setStyleSheet("background: none; background-color: #003669; color: #16ffff; font-size: 18px;") # self.upper_weight_label.setFixedSize(93, 22) self.upper_weight_label.setFixedSize(120, 29) self.upper_weight_label.move(outer_width//2 - 60, outer_height//2 - 46) # 额外文字(上位) self.upper_extra_label = QLabel("2.0方(预估)", self.upper_bg_widget) self.upper_extra_label.setAlignment(Qt.AlignCenter) # #262c38 #16ffff #131427 #003669 self.upper_extra_label.setStyleSheet("background: none; background-color: #003669; color: #16ffff; font-size: 18px;") self.upper_extra_label.setFixedSize(120, 29) self.upper_extra_label.move(outer_width//2 - 60, outer_height//2 - 13) # 料斗夹具图片(上位) # clamp_img = "料斗夹具.png" # clamp_pixmap = QPixmap(clamp_img) # if not clamp_pixmap.isNull(): # self.upper_clamp_label = QLabel() # self.upper_clamp_label.setPixmap(clamp_pixmap) # self.upper_clamp_label.setFixedSize(clamp_pixmap.width(), clamp_pixmap.height()) # layout.addWidget(self.upper_clamp_label, alignment=Qt.AlignCenter) # 料斗夹具图片(上位,固定152x60尺寸,图片自适应缩放) # 注意:目前由于给出的 料斗夹具图片尺寸大了,只能够先缩放,后期图片对了,可以用上面的 # clamp_img = "料斗夹具.png" # clamp_pixmap = QPixmap(clamp_img) # if not clamp_pixmap.isNull(): # self.upper_clamp_label = QLabel() # # 1. 固定QLabel尺寸为152x60 51,84 # self.upper_clamp_label.setFixedSize(152, 60) # # 2. 图片缩放到152x60(保持比例,平滑缩放) # scaled_pixmap = clamp_pixmap.scaled( # 152, 60, # Qt.KeepAspectRatio, # 保持图片原始比例,避免变形 # Qt.SmoothTransformation # 平滑缩放,提升显示效果 # ) # self.upper_clamp_label.setPixmap(scaled_pixmap) # # 3. 确保图片在QLabel中居中显示 # self.upper_clamp_label.setAlignment(Qt.AlignCenter) # layout.addWidget(self.upper_clamp_label, alignment=Qt.AlignCenter) # 夹具容器 self.upper_clamp_widget = ClampWidget() layout.addWidget(self.upper_clamp_widget, alignment=Qt.AlignCenter) self.upper_bg_widget.raise_() # 夹具图层位于 upper_bg_widget之下 # 按钮(上位料斗) self.upper_open_btn = CircularButton("开", group) # self.upper_open_btn.move(60, 153) # 上位料斗的开按钮位置 self.upper_open_btn.move(290, 90) # self.upper_close_btn = CircularButton("关", group) # self.upper_close_btn.move(233, 153) # 上位料斗的关按钮位置 self.upper_arch_btn = CircularButton("拱", group) self.upper_arch_btn.move(290, 37) # 上位料斗的破拱按钮位置 return group def connectSignalToSlot(self): self.upper_arch_btn.clicked.connect(self.onUpperArchBreaking) self.lower_arch_btn.clicked.connect(self.onLowerArchBreaking) self.upper_open_btn.clicked.connect(self.onUpperClampOpen) self.lower_open_btn.clicked.connect(self.onLowerClampOpen) @Slot() def onUpperClampOpen(self): self.upper_clamp_widget.testAnimation(target_angle=60, duration=6) # 测试,6秒打开60度 @Slot() def onLowerClampOpen(self): self.lower_clamp_widget.testAnimation(target_angle=25, duration=6) # 测试,6秒打开30度 @Slot() def onUpperArchBreaking(self): if self.upper_arch_breaking_status == False: # 不破拱状态 # 此时,点击按钮为开启破拱 self.upper_arch_breaking_status = True self.upper_arch_label.setHidden(False) self.upper_arch_breaking_signal.emit(self.upper_arch_breaking_status) else: # 破拱状态 # 此时,点击按钮为关闭破拱 self.upper_arch_breaking_status = False self.upper_arch_label.setHidden(True) self.upper_arch_breaking_signal.emit(self.upper_arch_breaking_status) @Slot() def onLowerArchBreaking(self): if self.lower_arch_breaking_status == False: # 不破拱状态 # 此时,点击按钮为开启破拱 self.lower_arch_breaking_status = True self.lower_arch_label.setHidden(False) self.lower_arch_breaking_signal.emit(self.lower_arch_breaking_status) else: # 破拱状态 # 此时,点击按钮为关闭破拱 self.lower_arch_breaking_status = False self.lower_arch_label.setHidden(True) self.upper_arch_breaking_signal.emit(self.lower_arch_breaking_status) def create_lower_hopper(self): """创建下位料斗Widget""" group = QWidget() # 下位的 料斗控件的固定尺寸 !!!! # 注意: 这里需要根据具体的料斗图片来修改 # group.setFixedSize(332, 280) group.setFixedSize(332, 222) # group.setStyleSheet("background-color: black") layout = QVBoxLayout(group) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) # 标题标签(下位) self.lower_title_label = QLabel("低位料斗") self.lower_title_label.setFixedSize(117, 23) self.lower_title_label.setAlignment(Qt.AlignCenter) # self.lower_title_label.setStyleSheet("color: #2fd3f2; font-size: 14px; font-weight: bold;") # self.lower_title_label.setStyleSheet("color: #0bffff; font-size: 18px;") self.lower_title_label.setStyleSheet(""" color: #0bffff; font-size: 18px; background-image: url(:/icons/images/文字标题底.png); background-repeat: no-repeat; background-position: center; margin-bottom: 4px; """) layout.addWidget(self.lower_title_label, alignment=Qt.AlignCenter) # 加载外框图片 outer_img = ":/icons/images/料斗1.png" outer_pixmap = QPixmap(outer_img) if outer_pixmap.isNull(): print(f"警告:图片 {outer_img} 加载失败,请检查路径!") return group outer_width = outer_pixmap.width() outer_height = outer_pixmap.height() # 背景容器(下位) self.lower_bg_widget = QWidget() self.lower_bg_widget.setFixedSize(outer_width, outer_height) self.lower_bg_widget.setStyleSheet(f"background-image: url({outer_img}); background-repeat: no-repeat; background-position: center;") layout.addWidget(self.lower_bg_widget, alignment=Qt.AlignCenter) # 内框图片(下位) inner_img = ":/icons/images/料斗2.png" inner_pixmap = QPixmap(inner_img) if not inner_pixmap.isNull(): self.lower_inner_label = QLabel(self.lower_bg_widget) self.lower_inner_label.setPixmap(inner_pixmap) self.lower_inner_label.setFixedSize(inner_pixmap.width(), inner_pixmap.height()) self.lower_inner_label.move(14, 9) # 状态图片(下位) status_img = ":/icons/images/料斗状态绿.png" status_pixmap = QPixmap(status_img) if not status_pixmap.isNull(): status_pixmap = status_pixmap.scaled(13, 13, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.lower_status_label = QLabel(self.lower_bg_widget) self.lower_status_label.setPixmap(status_pixmap) self.lower_status_label.move(22, 12) self.lower_status_label.setScaledContents(False) self.lower_status_label.setStyleSheet("background: none;") # 破拱图片(下位) arch_img = ":/icons/images/破拱.png" arch_pixmap = QPixmap(arch_img) if not arch_pixmap.isNull(): arch_pixmap = arch_pixmap.scaled(16, 13, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.lower_arch_label = QLabel(self.lower_bg_widget) self.lower_arch_label.setPixmap(arch_pixmap) self.lower_arch_label.move(outer_width - 39, 12) self.lower_arch_label.setStyleSheet("background: none;") self.lower_arch_label.setHidden(True) # 初始,不破拱状态,隐藏 # 重量文字(下位) self.lower_weight_label = QLabel("5000kg", self.lower_bg_widget) # self.lower_weight_label.setStyleSheet("background: none; background-color: #262c38; color: #79c053; font-size: 14px;font-weight: bold;") self.lower_weight_label.setStyleSheet("background: none; background-color: #003669; color: #16ffff; font-size: 18px;") self.lower_weight_label.setAlignment(Qt.AlignCenter) # self.lower_weight_label.setFixedSize(93, 22) self.lower_weight_label.setFixedSize(120, 29) # self.lower_weight_label.move(outer_width//2 - 46, outer_height//2 - 46) self.lower_weight_label.move(outer_width//2 - 60, outer_height//2 - 46) # 额外文字(下位) self.lower_extra_label = QLabel("开: 25°", self.lower_bg_widget) self.lower_extra_label.setAlignment(Qt.AlignCenter) # self.lower_extra_label.setStyleSheet("background: none; background-color: #262c38; color: #79c053; font-size: 14px;font-weight: bold;") self.lower_extra_label.setStyleSheet("background: none; background-color: #003669; color: #16ffff; font-size: 18px;") # self.lower_extra_label.setFixedSize(93, 22) self.lower_extra_label.setFixedSize(120, 29) # self.lower_extra_label.move(outer_width//2 - 46, outer_height//2 - 20) self.lower_extra_label.move(outer_width//2 - 60, outer_height//2 - 13) # 料斗夹具图片(下位) # clamp_img = "料斗夹具.png" # clamp_pixmap = QPixmap(clamp_img) # if not clamp_pixmap.isNull(): # self.lower_clamp_label = QLabel() # self.lower_clamp_label.setPixmap(clamp_pixmap) # self.lower_clamp_label.setFixedSize(clamp_pixmap.width(), clamp_pixmap.height()) # layout.addWidget(self.lower_clamp_label, alignment=Qt.AlignCenter) # 目前由于给出的 料斗夹具图片尺寸大了,只能够先缩放,后期图片对了,可以用上面的 # clamp_img = "料斗夹具.png" # clamp_pixmap = QPixmap(clamp_img) # if not clamp_pixmap.isNull(): # self.lower_clamp_label = QLabel() # # 1. 固定QLabel尺寸为152x60 # self.lower_clamp_label.setFixedSize(152, 60) # # 2. 图片缩放到152x60(保持比例,平滑缩放) # scaled_pixmap = clamp_pixmap.scaled( # 152, 60, # Qt.KeepAspectRatio, # 保持图片原始比例,避免变形 # Qt.SmoothTransformation # 平滑缩放,提升显示效果 # ) # self.lower_clamp_label.setPixmap(scaled_pixmap) # # 3. 确保图片在QLabel中居中显示 # self.lower_clamp_label.setAlignment(Qt.AlignCenter) # layout.addWidget(self.lower_clamp_label, alignment=Qt.AlignCenter) # 夹具容器 self.lower_clamp_widget = ClampWidget() layout.addWidget( self.lower_clamp_widget, alignment=Qt.AlignCenter) self.lower_bg_widget.raise_() # 夹具图层位于 self.lower_bg_widget之下 # 按钮(下位) self.lower_open_btn = CircularButton("开", group) # self.lower_open_btn.move(60, 233) # 下位料斗的开按钮位置 self.lower_open_btn.move(290, 90) # self.lower_close_btn = CircularButton("关", group) # self.lower_close_btn.move(233, 233) # 下位料斗的关按钮位置 self.lower_arch_btn = CircularButton("拱", group) self.lower_arch_btn.move(290, 34) # 下位料斗的破拱按钮位置 return group # 上料斗重量设置 def setUpperHopperWeight(self, weight:float): self.upper_weight_label.setText(f"{weight}kg") # 上料斗方量设置 def setUpperHopperVolume(self, volume: float): """Args: volume : 传入多少方 """ self.upper_extra_label.setText(f"{volume}方(预估)") # 下料斗重量设置 def setLowerHopperWeight(self, weight:float): self.lower_weight_label.setText(f"{weight}kg") # 下料斗开合角度设置 def setLowerHopperOpeningAngle(self, angle: float): """Args: angle : 传入多少度 (单位°) """ self.lower_extra_label.setText(f"开: {angle}°") # ------------------------------ # 设置上料斗状态(0=绿,1=黄,2=红) # ------------------------------ def setUpperArchStatus(self, status: int): """ 设置上料斗状态图片 Args: status: 状态值(0=绿,1=黄,2=红),非指定值不操作 """ # 过滤无效状态:不在0/1/2范围内则直接返回,保持当前图片 if status not in [0, 1, 2]: return # 状态-图片路径映射 # 注意:需要替换为实际的图片路径 status_img_map = { 0: ":/icons/images/料斗状态绿.png", 1: ":/icons/images/料斗状态黄.png", 2: ":/icons/images/料斗状态红.png" } img_path = status_img_map[status] # 加载并缩放图片 status_pixmap = QPixmap(img_path) if not status_pixmap.isNull(): status_pixmap = status_pixmap.scaled( 22, 22, Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.upper_status_label.setPixmap(status_pixmap) # ------------------------------ # 设置下料斗状态(0=绿,1=黄,2=红) # ------------------------------ def setLowerArchStatus(self, status: int): """ 设置下料斗状态图片 Args: status: 状态值(0=绿,1=黄,2=红),非指定值不操作 """ if status not in [0, 1, 2]: return # 注意:需要替换为实际的图片路径 status_img_map = { 0: ":/icons/images/料斗状态绿.png", 1: ":/icons/images/料斗状态黄.png", 2: ":/icons/images/料斗状态红.png" } img_path = status_img_map[status] status_pixmap = QPixmap(img_path) if not status_pixmap.isNull(): status_pixmap = status_pixmap.scaled( 22, 22, Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.lower_status_label.setPixmap(status_pixmap) # 隐藏上料斗 (用于上料斗移动) def hideUpperHopper(self): self.upper_title_label.hide() self.upper_bg_widget.hide() self.upper_clamp_widget.hide() self.upper_open_btn.hide() self.upper_arch_btn.hide() # 显示上料斗 (用于上料斗移动完成后恢复显示) def showUpperHopper(self): self.upper_title_label.setHidden(False) self.upper_bg_widget.setHidden(False) self.upper_clamp_widget.setHidden(False) self.upper_open_btn.setHidden(False) self.upper_arch_btn.setHidden(False) if __name__ == "__main__": app = QApplication(sys.argv) window = HopperWidget() window.setLowerHopperWeight(2000) window.setUpperHopperVolume(3.0) window.setLowerHopperOpeningAngle(45) window.setUpperArchStatus(2) window.setLowerArchStatus(1) window.show() sys.exit(app.exec())