class SVGButton(QPushButton): def __init__(self, text=None): super(SVGButton, self).__init__(text) self.layout = QHBoxLayout() self.setLayout(self.layout) self.svg = QSvgWidget("./assets/loading.svg", self) self.svg.setVisible(False) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.svg) def setEnabled(self, enabled): super().setEnabled(enabled) self.svg.setVisible(not enabled)
class ScrollWindow(QScrollArea): def __init__(self, *args, **kwargs): super(ScrollWindow, self).__init__(*args, **kwargs) # self.setAcceptDrops(True) # 2 self.resize(800, 600) self.setFrameShape(self.NoFrame) self.setWidgetResizable(True) self.setAlignment(Qt.AlignCenter) self._loadStart = False # 网格窗口 self._widget = GridWidget(self) self._widget.loadStarted.connect(self.setLoadStarted) self.setWidget(self._widget) #################################################### # 连接竖着的滚动条滚动事件 # self.verticalScrollBar().actionTriggered.connect(self.onActionTriggered) #################################################### # 进度条 self.loadWidget = QSvgWidget(self, minimumHeight=180, minimumWidth=180, visible=False) self.loadWidget.load(Svg_icon_loading) def setLoadStarted(self, started): self._loadStart = started self.loadWidget.setVisible(started) def onActionTriggered(self, action): # 这里要判断action=QAbstractSlider.SliderMove,可以避免窗口大小改变的问题 # 同时防止多次加载同一个url if action != QAbstractSlider.SliderMove or self._loadStart: return # 使用sliderPosition获取值可以同时满足鼠标滑动和拖动判断 if self.verticalScrollBar().sliderPosition() == self.verticalScrollBar( ).maximum(): # 可以下一页了 self._widget.load() def resizeEvent(self, event): super(ScrollWindow, self).resizeEvent(event) self.loadWidget.setGeometry( int((self.width() - self.loadWidget.minimumWidth()) / 2), int((self.height() - self.loadWidget.minimumHeight()) / 2), self.loadWidget.minimumWidth(), self.loadWidget.minimumHeight())
class Window(QListWidget): Page = 0 def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.resize(800, 600) self.setFrameShape(self.NoFrame) # 无边框 self.setFlow(self.LeftToRight) # 从左到右 self.setWrapping(True) # 这三个组合可以达到和FlowLayout一样的效果 self.setResizeMode(self.Adjust) self._loadStart = False # 连接竖着的滚动条滚动事件 self.verticalScrollBar().actionTriggered.connect( self.onActionTriggered) # 进度条 self.loadWidget = QSvgWidget(self, minimumHeight=120, minimumWidth=120, visible=False) self.loadWidget.load(Svg_icon_loading) # 异步网络下载管理器 self._manager = QNetworkAccessManager(self) self._manager.finished.connect(self.onFinished) def load(self): if self.Page == -1: return self._loadStart = True self.loadWidget.setVisible(True) # 延迟一秒后调用目的在于显示进度条 QTimer.singleShot(1000, self._load) def _load(self): print("load url:", Url.format(self.Page * 30)) url = QUrl(Url.format(self.Page * 30)) self._manager.get(QNetworkRequest(url)) def onFinished(self, reply): # 请求完成后会调用该函数 req = reply.request() # 获取请求 iwidget = req.attribute(QNetworkRequest.User + 1, None) path = req.attribute(QNetworkRequest.User + 2, None) html = reply.readAll().data() reply.deleteLater() del reply if iwidget and path and html: # 这里是图片下载完毕 open(path, "wb").write(html) iwidget.setCover(path) return # 解析网页 self._parseHtml(html) self._loadStart = False self.loadWidget.setVisible(False) def _parseHtml(self, html): # encoding = chardet.detect(html) or {} # html = html.decode(encoding.get("encoding","utf-8")) html = HTML(html) # 查找所有的li list_item lis = html.xpath("//li[@class='list_item']") if not lis: self.Page = -1 # 后面没有页面了 return self.Page += 1 self._makeItem(lis) def _makeItem(self, lis): for li in lis: a = li.find("a") video_url = a.get("href") # 视频播放地址 img = a.find("img") cover_url = "http:" + img.get("r-lazyload") # 封面图片 figure_title = img.get("alt") # 电影名 figure_info = a.find("div/span") figure_info = "" if figure_info is None else figure_info.text # 影片信息 figure_score = "".join(li.xpath(".//em/text()")) # 评分 # 主演 figure_desc = "<span style=\"font-size: 12px;\">主演:</span>" + \ "".join([Actor.format(**dict(fd.items())) for fd in li.xpath(".//div[@class='figure_desc']/a")]) # 播放数 figure_count = ( li.xpath(".//div[@class='figure_count']/span/text()") or [""])[0] path = "cache/{0}.jpg".format( os.path.splitext(os.path.basename(video_url))[0]) cover_path = "Data/pic_v.png" if os.path.isfile(path): cover_path = path iwidget = ItemWidget(cover_path, figure_info, figure_title, figure_score, figure_desc, figure_count, video_url, cover_url, path, self._manager, self) item = QListWidgetItem(self) item.setSizeHint(iwidget.sizeHint()) self.setItemWidget(item, iwidget) def onActionTriggered(self, action): # 这里要判断action=QAbstractSlider.SliderMove,可以避免窗口大小改变的问题 # 同时防止多次加载同一个url if action != QAbstractSlider.SliderMove or self._loadStart: return # 使用sliderPosition获取值可以同时满足鼠标滑动和拖动判断 if self.verticalScrollBar().sliderPosition() == self.verticalScrollBar( ).maximum(): # 可以下一页了 self.load() def resizeEvent(self, event): super(Window, self).resizeEvent(event) self.loadWidget.setGeometry( int((self.width() - self.loadWidget.minimumWidth()) / 2), int((self.height() - self.loadWidget.minimumHeight()) / 2), self.loadWidget.minimumWidth(), self.loadWidget.minimumHeight())
class GUI(QMainWindow): def __init__(self, app, bot, stream): # app super(GUI, self).__init__() QDir.setCurrent(bundle_dir) self.app = app # window info self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint) window_icon = QIcon('./assets/favicon.ico') self.setWindowTitle('Discord Audio Pipe') self.app.setWindowIcon(window_icon) self.position = None # discord self.bot = bot self.voice = None self.stream = stream # layout central = QWidget() layout = QGridLayout() central.setLayout(layout) # loading self.info = QLabel('Connecting...') self.loading = QSvgWidget('./assets/loading.svg') # devices self.devices = QComboBox(self) self.devices.setItemDelegate(QStyledItemDelegate()) self.devices.setPlaceholderText('None') device_lb = QLabel('Devices') device_lb.setObjectName('label') for device, idx in sound.query_devices().items(): self.devices.addItem(device + ' ', idx) # servers self.servers = QComboBox(self) self.servers.setItemDelegate(QStyledItemDelegate()) self.servers.setPlaceholderText('None') server_lb = QLabel('Servers ') server_lb.setObjectName('label') # channels self.channels = QComboBox(self) self.channels.setItemDelegate(QStyledItemDelegate()) self.channels.setPlaceholderText('None') channel_lb = QLabel('Channels ') channel_lb.setObjectName('label') # mute self.mute = QPushButton('Mute', self) self.mute.setObjectName('mute') # add widgets layout.addWidget(self.info, 0, 0, 1, 3) layout.addWidget(self.loading, 0, 3, alignment=Qt.AlignHCenter) layout.addWidget(device_lb, 1, 0) layout.addWidget(self.devices, 2, 0) layout.addWidget(server_lb, 1, 1) layout.addWidget(self.servers, 2, 1) layout.addWidget(channel_lb, 1, 2) layout.addWidget(self.channels, 2, 2) layout.addWidget(self.mute, 2, 3) # events self.devices.currentTextChanged.connect(self.change_device) self.servers.currentTextChanged.connect( lambda: asyncio.ensure_future(self.change_server())) self.channels.currentTextChanged.connect( lambda: asyncio.ensure_future(self.change_channel())) self.mute.clicked.connect(self.toggle_mute) # build window titlebar = TitleBar(self) self.setMenuWidget(titlebar) self.setCentralWidget(central) self.disable_ui() # load styles QFontDatabase.addApplicationFont('./assets/Roboto-Black.ttf') with open('./assets/style.qss', 'r') as qss: self.app.setStyleSheet(qss.read()) # show window self.show() def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.position = event.pos() event.accept() def mouseMoveEvent(self, event): if self.position is not None and event.buttons() == Qt.LeftButton: self.move(self.pos() + event.pos() - self.position) event.accept() def mouseReleaseEvent(self, event): self.position = None event.accept() def disable_ui(self): self.loading.setVisible(True) self.devices.setEnabled(False) self.servers.setEnabled(False) self.channels.setEnabled(False) self.mute.setEnabled(False) def enable_ui(self): self.loading.setVisible(False) self.devices.setEnabled(True) self.servers.setEnabled(True) self.channels.setEnabled(True) self.mute.setEnabled(True) async def run_Qt(self, interval=0.01): while True: QCoreApplication.processEvents(QEventLoop.AllEvents, interval * 1000) await asyncio.sleep(interval) def resize_combobox(self, combobox): font = combobox.property('font') metrics = QFontMetrics(font) min_width = 0 for i in range(combobox.count()): size = metrics.horizontalAdvance(combobox.itemText(i)) if size > min_width: min_width = size combobox.setMinimumWidth(min_width + 30) async def ready(self): await self.bot.wait_until_ready() self.info.setText(f'Logged in as: {self.bot.user.name}') for guild in self.bot.guilds: self.servers.addItem(guild.name, guild) self.resize_combobox(self.servers) self.enable_ui() def change_device(self): try: selection = self.devices.currentData() self.mute.setText('Mute') if self.voice is not None: self.voice.stop() self.stream.change_device(selection) if self.voice.is_connected(): self.voice.play(discord.PCMAudio(self.stream)) else: self.stream.change_device(selection) except Exception: logging.exception('Error on change_device') async def change_server(self): try: selection = self.servers.currentData() self.channels.clear() self.channels.addItem('None', None) for channel in selection.channels: if isinstance(channel, discord.VoiceChannel): self.channels.addItem(channel.name, channel) self.resize_combobox(self.channels) except Exception: logging.exception('Error on change_server') async def change_channel(self): try: selection = self.channels.currentData() self.mute.setText('Mute') self.disable_ui() if selection is not None: not_connected = (self.voice is None or self.voice is not None and not self.voice.is_connected()) if not_connected: self.voice = await selection.connect(timeout=10) else: await self.voice.move_to(selection) not_playing = (self.devices.currentData() is not None and not self.voice.is_playing()) if not_playing: self.voice.play(discord.PCMAudio(self.stream)) else: if self.voice is not None: await self.voice.disconnect() except Exception: logging.exception('Error on change_channel') finally: self.enable_ui() def toggle_mute(self): try: if self.voice is not None: if self.voice.is_playing(): self.voice.pause() self.mute.setText('Resume') else: self.voice.resume() self.mute.setText('Mute') except Exception: logging.exception('Error on toggle_mute')
class MissevanKit(QMainWindow, Ui_mainWindow): def __init__(self, parent=None): super(MissevanKit, self).__init__(parent) self.setupUi(self) # self.set_style() self.center() self.setTab1() self.setTab2() self.setTab3() self.setTab4() self.gen_data_thread = None self.collect_thread = None self.tab_1_log = gen_date_filename(APP_LogPath, "数据采集日志.txt") self.tab_2_log = gen_date_filename(APP_LogPath, "数据处理日志.txt") # self.tabWidget.setCurrentIndex(0) def center(self): # 实现窗体在屏幕中央 screen = QDesktopWidget().screenGeometry() size = self.geometry() # 同上 self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 4) def setTab1(self): self.pushButton.clicked.connect(self.start_collect) self.pushButton_2.clicked.connect(lambda: self.collect_progress(STOP)) self.pushButton_9.clicked.connect(self.set_choose_rect_brower) # self.pushButton_4.clicked.connect(lambda: self.set_browser_collapse(self.textBrowser_3)) def gen_tab1_config(self): # worktime # 是否只是工作日抓取 GLOBAL_CONFIG[ONLY_WORK_DAY] = False if self.checkBox.isChecked(): GLOBAL_CONFIG[ONLY_WORK_DAY] = True if self.radioButton_5.isChecked(): if self.textEdit.toPlainText(): try: GLOBAL_CONFIG[WORK_TIME] = [ int(i) for i in self.textEdit.toPlainText().split() ] except: self.echo_error('抓取的时间点输入格式不对,24小时制,用空格分隔') return False else: self.echo_error('抓取的时间点(小时)为空,请检查') return False elif self.radioButton_4.isChecked(): GLOBAL_CONFIG[WORK_TIME] = [i for i in range(24)] elif self.radioButton_3.isChecked(): GLOBAL_CONFIG[WORK_TIME] = [i for i in range(7, 9) ] + [i for i in range(17, 19)] elif self.radioButton_2.isChecked(): GLOBAL_CONFIG[WORK_TIME] = [i for i in range(17, 19)] elif self.radioButton.isChecked(): GLOBAL_CONFIG[WORK_TIME] = [i for i in range(7, 9)] if self.textEdit_left.toPlainText(): # 左下角换到左上角 left_p = self.textEdit_left.toPlainText().split(',') right_p = self.textEdit_right.toPlainText().split(',') GLOBAL_CONFIG[LEFT_POINT] = [left_p[0], right_p[1]] GLOBAL_CONFIG[RIGHT_POINT] = [right_p[0], left_p[1]] else: self.echo_error('矩形区域为空,请检查') return False if self.textEdit_9.toPlainText(): try: spacing_time = int(self.textEdit_9.toPlainText()) if spacing_time < 0: self.echo_error('间隔时间不能小于0,请重新输入') return False GLOBAL_CONFIG[SPACING_TIME] = spacing_time except: self.echo_error('间隔时间输入错误,请检查') else: self.echo_error('间隔时间为空,请检查') return False return True def start_collect(self): if self.gen_tab1_config(): write_to_log(self.tab_1_log, "程序开始运行...") write_to_log(self.tab_1_log, GLOBAL_CONFIG) # 初始化 if self.collect_thread: self.collect_thread.terminate() self.collect_thread = None self.collect_thread = CollectThread() self.collect_thread.sinOut.connect(self.collect_progress) self.collect_thread.start() # 循环滚动 self.progressBar.setMaximum(0) self.pushButton.setEnabled(False) self.pushButton_2.setEnabled(True) def collect_progress(self, flag): # 向列表控件中添加条目 if flag == STOP: write_to_log(self.tab_1_log, "用户终止程序") self.collect_thread.terminate() GLOBAL_CONFIG[THREAD_FLAG] = False self.pushButton.setEnabled(True) self.pushButton_2.setEnabled(False) self.progressBar.setMaximum(100) elif flag == ERROR: write_to_log(self.tab_1_log, "系统发生错误,请检查") self.collect_thread.terminate() GLOBAL_CONFIG[THREAD_FLAG] = False self.pushButton.setEnabled(True) self.pushButton_2.setEnabled(False) self.progressBar.setMaximum(100) else: write_to_log(self.tab_1_log, flag) def set_date_time(self): # datetime = Qcommon_roadDateTime.currentDateTime() pass def set_choose_rect_brower(self): map_win = MapWindow(self) map_win.rectSignal.connect(self.getRect) map_win.exec_() def set_browser_collapse(self, browser): if browser.isVisible(): browser.setVisible(False) browser.clear() else: browser.setVisible(True) def getRect(self, rect): if rect: leftb = rect.split(' ')[0] right = rect.split(' ')[1] self.textEdit_left.setText(leftb) self.textEdit_right.setText(right) def setTab2(self): self.pushButton_14.clicked.connect(self.start_gen_data) self.pushButton_7.clicked.connect(self.choose_data_dir) # self.pushButton_choose_road.clicked.connect(self.choose_road_dialog) self.pushButton_13.clicked.connect( lambda: self.gen_data_progress(STOP)) # self.textEdit_red.selectionChanged.connect(self.change_green_threshold) def change_green_threshold(self): try: red = float(self.textEdit_red.toPlainText()) yellow = float(self.textEdit_yellow.toPlainText()) green = float(self.textEdit_green.toPlainText()) if is_float(red) and is_float(yellow) and is_float(green): if not red > yellow > green: self.echo_error("输入错误,拥堵比例关系应该是红点大于橙黄点大于黄色") return False GLOBAL_CONFIG[RED_THRESHOLD] = red GLOBAL_CONFIG[YELLOW_THRESHOLD] = yellow GLOBAL_CONFIG[GREEN_THRESHOLD] = green return True else: self.echo_error("输入错误 ,需要为(0-1)的小数") return False except: self.echo_error("输入错误,需要为(0-1)的小数") return False def gen_tab2_config(self): if not self.change_green_threshold(): return False if self.radioButton_9.isChecked(): GLOBAL_CONFIG[GEN_ROAD_TYPE] = ALL_ROAD elif self.radioButton_10.isChecked(): GLOBAL_CONFIG[GEN_ROAD_TYPE] = FAST_ROAD elif self.radioButton_11.isChecked(): GLOBAL_CONFIG[GEN_ROAD_TYPE] = COMMON_ROAD data_dir = self.textEdit_7.toPlainText() if data_dir: flag = False for roots, dirs, files in os.walk(data_dir): for f in files: if f.endswith('npz'): flag = True if not flag: self.echo_error('数据所在路径中没有所需要的数据文件,请检查') return False if data_dir.endswith(os.sep): GLOBAL_CONFIG[DATA_DIR] = data_dir else: GLOBAL_CONFIG[DATA_DIR] = data_dir + os.sep else: self.echo_error('数据所在路径不能为空,请检查') return False return True def choose_road_dialog(self): road, ok = QInputDialog.getItem(self, "选择指定道路", "'全部'代表所有道路\n\n请选择道路:", ROAD_DATAS, 1, True) if ok: if road: self.textEdit_11.setText(road) if road == ROAD_DATAS[0]: pass def start_gen_data(self): if self.gen_tab2_config(): print(GLOBAL_CONFIG) write_to_log(self.tab_2_log, "程序开始运行...") write_to_log(self.tab_2_log, GLOBAL_CONFIG) self.pushButton_14.setEnabled(False) self.pushButton_13.setEnabled(True) if self.gen_data_thread: self.gen_data_thread.terminate() self.gen_data_thread = None self.progressBar_3.setValue(0) self.gen_data_thread = GenDataThread() self.gen_data_thread.sinOut.connect(self.gen_data_progress) self.gen_data_thread.start() def gen_data_progress(self, flag): if flag == STOP: write_to_log(self.tab_2_log, "用户终止程序") self.gen_data_thread.terminate() GLOBAL_CONFIG[THREAD_FLAG] = False self.pushButton_14.setEnabled(True) self.pushButton_13.setEnabled(False) self.progressBar_3.setValue(0) elif flag == ERROR: write_to_log(self.tab_2_log, "系统崩溃,请查明原因") self.echo("系统崩溃,请查明原因") self.gen_data_thread.terminate() GLOBAL_CONFIG[THREAD_FLAG] = False self.pushButton_14.setEnabled(True) self.pushButton_13.setEnabled(False) self.progressBar_3.setValue(0) elif flag == SUCCESS: write_to_log(self.tab_2_log, "数据生成完成,可进入识别或评价标签进行处理") self.echo("数据生成完成,可进入识别或评价标签进行处理") self.webview.reload() GLOBAL_CONFIG[THREAD_FLAG] = False self.pushButton_14.setEnabled(True) self.pushButton_13.setEnabled(False) self.progressBar_3.setValue(100) else: try: flag = int(flag) self.progressBar_3.setValue(flag) except: write_to_log(self.tab_2_log, flag) def choose_data_dir(self): dir = QFileDialog.getExistingDirectory(self, "选择数据文件夹", APP_DirPath) if dir: self.textEdit_7.setText(dir) def setTab3(self): self.setLoading() self.setBrower() def setLoading(self): self.loadWidget = QSvgWidget() self.loadWidget.setMaximumSize(QSize(60, 60)) self.loadWidget.load(Svg_icon_loading) self.gridLayout_2.addWidget(self.loadWidget) self.loadWidget.setVisible(False) def setLoadStarted(self): self.loadWidget.setVisible(True) print('开始') def setLoadFinished(self, ): self.webview.setVisible(True) self.loadWidget.setVisible(False) def setBrower(self): self.webview = QWebEngineView() html_path = APP_HtmlPath + os.sep + "index.html" self.webview.load(QUrl.fromLocalFile(html_path)) self.gridLayout_2.addWidget(self.webview) self.webview.setVisible(False) self.webview.page().loadStarted.connect(self.setLoadStarted) self.webview.page().loadFinished.connect(self.setLoadFinished) def setTab4(self): self.pushButton_16.clicked.connect(self.export_excel) self.pushButton_15.clicked.connect(self.gen_table) def gen_table(self): time_weight = self.textEdit_timeweight.toPlainText() if time_weight: time_weight = float(time_weight) else: self.echo_error('拥堵时长权重不能为空,请检查') return False length_weight = self.textEdit_lengthweight.toPlainText() if length_weight: length_weight = float(length_weight) else: self.echo_error('拥堵距离权重不能为空,请检查') return False # 表格处理要完全清除 self.tableWidget.clear() self.tableWidget.setRowCount(0) self.tableWidget.setColumnCount(0) self.tableWidget.setSortingEnabled(True) self.tableWidget.horizontalHeader().setStyleSheet( "background-color: gray") self.tableWidget.setSelectionBehavior(1) self.tableWidget.horizontalHeader().setStretchLastSection(True) self.tableWidget.horizontalHeader().setSectionResizeMode(1) self.tableWidget.setShowGrid(True) file = open(JSON_FILE_PATH, 'r', encoding='utf-8') json_datas = json.load(file) time_max = max([float(x['jam_time']) for x in json_datas]) length_max = max([float(x['distance']) for x in json_datas]) json_datas.sort( key=lambda x: time_weight * float(x['jam_time']) / time_max + length_weight * float(x['distance']) / length_max, reverse=True) self.tableWidget.setColumnCount(len(TITLE_ROW)) self.tableWidget.setRowCount(len(json_datas)) self.tableWidget.setHorizontalHeaderLabels(TITLE_ROW) for row_index, json_data in enumerate(json_datas): no = json_data[JSON_NO] distance = json_data[JSON_DISTANCE] jam_time = json_data[JSON_JAM_TIME] start_point = json_data[JSON_START_POINT] start_place = json_data[JSON_START_PLACE] end_point = json_data[JSON_END_POINT] end_place = json_data[JSON_END_PLACE] # TODO date_type = json_data[JSON_DAY] jam_type = json_data[JSON_TYPE] if jam_type == 'red': color = '红色' elif jam_type == 'yellow': color = '橙黄' else: color = '黄色' if date_type == 'morning': day = '早高峰' else: day = '晚高峰' row_data = [ no, day, start_place, str(start_point).replace('[', '').replace(']', ''), end_place, str(end_point).replace('[', '').replace(']', ''), float(distance), color, jam_time ] for col_index, item in enumerate(row_data): qitem = QTableWidgetItem() qitem.setTextAlignment(Qt.AlignCenter) # set data好,不然text排序只按字符串排 qitem.setData(0, item) self.tableWidget.setItem(row_index, col_index, qitem) def export_excel(self): dir = QFileDialog.getExistingDirectory(self, "EXCEL文件保存到") if dir: file_path = gen_date_filename(dir, '-拥堵分析.xlsx') workbook = xw.Book() worksheet = workbook.sheets[0] rows = self.tableWidget.rowCount() cols = self.tableWidget.columnCount() rows_data = [] for row in range(rows): row_data = [] for col in range(cols): data = self.tableWidget.item(row, col).text() row_data.append(data) rows_data.append(row_data) worksheet.range('A1').value = EXCEL_TITLE_ROW worksheet.range('A2').value = rows_data workbook.save(file_path) workbook.close() self.echo(f"导出完成,EXCEL文件所在路径:\n{file_path}") else: self.echo_error("EXCEL文件存储路径不能为空") return False def echo(self, value): '''显示对话框返回值''' box = QMessageBox(self) box.information(self, "操作成功", "{}\n".format(value), QMessageBox.Ok) def echo_error(self, value): box = QMessageBox(self) box.warning(self, "错误", "{}\n".format(value), QMessageBox.Ok)
class PaneSelectItem(QWidget): pane_selected = pyqtSignal(QWidget) def __init__(self, icon_inactive_filename, icon_active_filename, icon_hover_filename, label_text=None, *args): super(PaneSelectItem, self).__init__(*args) self.setMouseTracking(True) self.setAutoFillBackground(True) self.active = False self.active_color = QColor(239, 0, 183) self.background_color = QColor(30, 30, 30) self.v_layout = QVBoxLayout() self.v_layout.addStretch() self.icon_layout = QHBoxLayout() self.icon_layout.addStretch() self.icon_inactive = QSvgWidget(icon_inactive_filename) self.set_icon_size(self.icon_inactive, 200, 43) self.icon_active = QSvgWidget(icon_active_filename) self.set_icon_size(self.icon_active, 200, 43) self.icon_active.setVisible(False) self.icon_hover = QSvgWidget(icon_hover_filename) self.set_icon_size(self.icon_hover, 200, 43) self.icon_hover.setVisible(False) self.icon_layout.addWidget(self.icon_inactive) self.icon_layout.addWidget(self.icon_active) self.icon_layout.addWidget(self.icon_hover) self.icon_layout.addStretch() self.v_layout.addLayout(self.icon_layout) if label_text is not None: self.label_layout = QHBoxLayout() self.label_layout.addStretch() self.label = QLabel() self.label.setStyleSheet("QLabel {color: #ffffff;}") self.label.setVisible(False) self.label.setText(label_text) self.label_layout.addWidget(self.label) self.label_layout.addStretch() self.v_layout.addLayout(self.label_layout) else: self.label = None self.v_layout.addStretch() self.setLayout(self.v_layout) @staticmethod def set_icon_size(svg_widget, width, height): svg_widget.setMaximumHeight(height) svg_widget.setMaximumWidth(width) svg_widget.setMinimumHeight(height) svg_widget.setMinimumWidth(width) def set_active(self, state): self.active = state self.icon_active.setVisible(self.active) if self.active: palette = self.palette() palette.setColor(self.backgroundRole(), self.active_color) self.setPalette(palette) if self.label is not None: self.label.setVisible(True) self.label.setStyleSheet("color: #000000;") self.icon_active.setVisible(True) self.icon_inactive.setVisible(False) self.icon_hover.setVisible(False) else: self.icon_inactive.setVisible(True) self.icon_hover.setVisible(False) self.icon_active.setVisible(False) palette = self.palette() palette.setColor(self.backgroundRole(), self.background_color) self.setPalette(palette) if self.label is not None: self.label.setVisible(False) self.label.setStyleSheet("QLabel {color: #ffffff;}") def enterEvent(self, event): if not self.active: self.icon_hover.setVisible(True) self.icon_inactive.setVisible(False) self.icon_active.setVisible(False) if self.label is not None: self.label.setVisible(True) def leaveEvent(self, event): if not self.active: self.icon_hover.setVisible(False) self.icon_inactive.setVisible(True) self.icon_active.setVisible(False) if self.label is not None: self.label.setVisible(self.active) def mousePressEvent(self, event): self.pane_selected.emit(self)