class DyStockTradeStrategyMarketMonitorWidget(QWidget): """ 股票策略实时监控窗口,动态创建 """ signal = QtCore.pyqtSignal(type(DyEvent())) def __init__(self, eventEngine, strategyCls, strategyState): super().__init__() self._eventEngine = eventEngine self._strategyCls = strategyCls self._cloneDataWidgets = [] self._registerEvent() self._initUi(strategyState) def _initUi(self, strategyState): self._dataWidget = DyStockTradeStrategyMarketMonitorDataWidget( self._strategyCls, self) self._indWidget = DyStockTradeStrategyMarketMonitorIndWidget( self._eventEngine, self._strategyCls, strategyState) self._dataLabel = QLabel('数据') self._indLabel = QLabel('指示') grid = QGridLayout() grid.setSpacing(0) grid.addWidget(self._dataLabel, 0, 0) grid.addWidget(self._dataWidget, 1, 0) grid.addWidget(self._indLabel, 2, 0) grid.addWidget(self._indWidget, 3, 0) grid.setRowStretch(0, 1) grid.setRowStretch(1, 30) grid.setRowStretch(2, 1) grid.setRowStretch(3, 30) self.setLayout(grid) # set menu for labels self._dataLabel.setContextMenuPolicy(Qt.CustomContextMenu) self._dataLabel.customContextMenuRequested.connect( self._showDataLabelContextMenu) self._indLabel.setContextMenuPolicy(Qt.CustomContextMenu) self._indLabel.customContextMenuRequested.connect( self._showIndLabelContextMenu) self._dataLabelMenu = QMenu(self) action = QAction('叠加', self) action.triggered.connect(self._overlapAct) self._dataLabelMenu.addAction(action) action = QAction('克隆', self) action.triggered.connect(self._cloneDataWidgetAct) self._dataLabelMenu.addAction(action) self._indLabelMenu = QMenu(self) action = QAction('叠加', self) action.triggered.connect(self._overlapAct) self._indLabelMenu.addAction(action) def _stockMarketMonitorUiHandler(self, event): if 'data' in event.data: data = event.data['data']['data'] new = event.data['data']['new'] strategyCls = event.data['class'] if strategyCls.maxUiDataRowNbr is not None: data = data[:strategyCls.maxUiDataRowNbr] self._dataWidget.update(data, new) for w in self._cloneDataWidgets: w.update(data, new) if 'ind' in event.data: self._indWidget.update(event.data['ind']) def _signalEmitWrapper(self, event): """ !!!Note: The value of signal.emit will always be changed each time you getting. """ self.signal.emit(event) def _registerEvent(self): self.signal.connect(self._stockMarketMonitorUiHandler) self._eventEngine.register( DyEventType.stockMarketMonitorUi + self._strategyCls.name, self._signalEmitWrapper) def _unregisterEvent(self): self.signal.disconnect(self._stockMarketMonitorUiHandler) self._eventEngine.unregister( DyEventType.stockMarketMonitorUi + self._strategyCls.name, self._signalEmitWrapper) def closeEvent(self, event): self._dataWidget.close() self._indWidget.close() self._unregisterEvent() return super().closeEvent(event) def _showDataLabelContextMenu(self, position): self._dataLabelMenu.popup(QCursor.pos()) def _showIndLabelContextMenu(self, position): self._indLabelMenu.popup(QCursor.pos()) def _overlapAct(self): grid = self.layout() # remove self._dataLabel.setText('') self._indLabel.setText('') grid.removeWidget(self._dataLabel) grid.removeWidget(self._dataWidget) grid.removeWidget(self._indLabel) grid.removeWidget(self._indWidget) # add self._tabWidget = QTabWidget() self._tabWidget.addTab(self._dataWidget, '数据') self._tabWidget.addTab(self._indWidget, '指示') grid.addWidget(self._tabWidget, 0, 0) grid.setRowStretch(0, 1) grid.setRowStretch(1, 0) grid.setRowStretch(2, 0) grid.setRowStretch(3, 0) # 设置Tab右键菜单事件 tabBar = self._tabWidget.tabBar() tabBar.setContextMenuPolicy(Qt.CustomContextMenu) tabBar.customContextMenuRequested.connect(self._showTabContextMenu) # 创建TabBar菜单 self._tabBarMenu = QMenu(self) action = QAction('平铺', self) action.triggered.connect(self._flatAct) self._tabBarMenu.addAction(action) def _showTabContextMenu(self, position): self._tabBarMenu.popup(QCursor.pos()) def _flatAct(self): grid = self.layout() # remove self._tabWidget.removeTab(0) self._tabWidget.removeTab(0) grid.removeWidget(self._tabWidget) self._tabWidget.hide() # add self._dataLabel.setText('数据') self._indLabel.setText('指示') grid.addWidget(self._dataLabel, 0, 0) grid.addWidget(self._dataWidget, 1, 0) grid.addWidget(self._indLabel, 2, 0) grid.addWidget(self._indWidget, 3, 0) self._dataWidget.show() self._indWidget.show() grid.setRowStretch(0, 1) grid.setRowStretch(1, 30) grid.setRowStretch(2, 1) grid.setRowStretch(3, 30) def removeCloneDataWidget(self, cloneWidget): try: self._cloneDataWidgets.remove(cloneWidget) except: pass def _cloneDataWidgetAct(self): dataWidget = self._dataWidget.clone() self._cloneDataWidgets.append(dataWidget) dataWidget.setWindowTitle('策略[{}]: 数据'.format( self._strategyCls.chName)) dataWidget.showMaximized()
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.settings = QSettings("Vial", "Vial") themes.set_theme(self.get_theme()) self.current_device = None self.devices = [] # create empty VIA definitions. Easier than setting it to none and handling a bunch of exceptions self.via_stack_json = {"definitions": {}} self.sideload_json = None self.sideload_vid = self.sideload_pid = -1 self.combobox_devices = QComboBox() self.combobox_devices.currentIndexChanged.connect( self.on_device_selected) self.btn_refresh_devices = QToolButton() self.btn_refresh_devices.setToolButtonStyle(Qt.ToolButtonTextOnly) self.btn_refresh_devices.setText(tr("MainWindow", "Refresh")) self.btn_refresh_devices.clicked.connect(self.on_click_refresh) layout_combobox = QHBoxLayout() layout_combobox.addWidget(self.combobox_devices) layout_combobox.addWidget(self.btn_refresh_devices) self.layout_editor = LayoutEditor() self.keymap_editor = KeymapEditor(self.layout_editor) self.firmware_flasher = FirmwareFlasher(self) self.macro_recorder = MacroRecorder() self.matrix_tester = MatrixTest(self.layout_editor) self.editors = [(self.keymap_editor, "Keymap"), (self.layout_editor, "Layout"), (self.macro_recorder, "Macros"), (self.matrix_tester, "Matrix tester"), (self.firmware_flasher, "Firmware updater")] Unlocker.global_layout_editor = self.layout_editor self.tabs = QTabWidget() self.refresh_tabs() self.lbl_no_devices = QLabel( tr( "MainWindow", 'No devices detected. Connect a Vial-compatible device and press ' '"Refresh"\n' 'or select "File" → "Download VIA definitions" in order to enable' ' support for VIA keyboards.')) self.lbl_no_devices.setAlignment(Qt.AlignCenter) layout = QVBoxLayout() layout.addLayout(layout_combobox) layout.addWidget(self.tabs) layout.addWidget(self.lbl_no_devices) layout.setAlignment(self.lbl_no_devices, Qt.AlignHCenter) w = QWidget() w.setLayout(layout) self.setCentralWidget(w) self.init_menu() # cache for via definition files self.cache_path = QStandardPaths.writableLocation( QStandardPaths.CacheLocation) if not os.path.exists(self.cache_path): os.makedirs(self.cache_path) # check if the via defitions already exist if os.path.isfile(os.path.join(self.cache_path, "via_keyboards.json")): with open(os.path.join(self.cache_path, "via_keyboards.json")) as vf: self.via_stack_json = json.load(vf) vf.close() # make sure initial state is valid self.on_click_refresh() def init_menu(self): layout_load_act = QAction(tr("MenuFile", "Load saved layout..."), self) layout_load_act.setShortcut("Ctrl+O") layout_load_act.triggered.connect(self.on_layout_load) layout_save_act = QAction(tr("MenuFile", "Save current layout..."), self) layout_save_act.setShortcut("Ctrl+S") layout_save_act.triggered.connect(self.on_layout_save) sideload_json_act = QAction(tr("MenuFile", "Sideload VIA JSON..."), self) sideload_json_act.triggered.connect(self.on_sideload_json) download_via_stack_act = QAction( tr("MenuFile", "Download VIA definitions"), self) download_via_stack_act.triggered.connect(self.load_via_stack_json) load_dummy_act = QAction(tr("MenuFile", "Load dummy JSON..."), self) load_dummy_act.triggered.connect(self.on_load_dummy) exit_act = QAction(tr("MenuFile", "Exit"), self) exit_act.setShortcut("Ctrl+Q") exit_act.triggered.connect(qApp.exit) file_menu = self.menuBar().addMenu(tr("Menu", "File")) file_menu.addAction(layout_load_act) file_menu.addAction(layout_save_act) file_menu.addSeparator() file_menu.addAction(sideload_json_act) file_menu.addAction(download_via_stack_act) file_menu.addAction(load_dummy_act) file_menu.addSeparator() file_menu.addAction(exit_act) keyboard_unlock_act = QAction(tr("MenuSecurity", "Unlock"), self) keyboard_unlock_act.triggered.connect(self.unlock_keyboard) keyboard_lock_act = QAction(tr("MenuSecurity", "Lock"), self) keyboard_lock_act.triggered.connect(self.lock_keyboard) keyboard_reset_act = QAction( tr("MenuSecurity", "Reboot to bootloader"), self) keyboard_reset_act.triggered.connect(self.reboot_to_bootloader) keyboard_layout_menu = self.menuBar().addMenu( tr("Menu", "Keyboard layout")) keymap_group = QActionGroup(self) selected_keymap = self.settings.value("keymap") for idx, keymap in enumerate(KEYMAPS): act = QAction(tr("KeyboardLayout", keymap[0]), self) act.triggered.connect( lambda checked, x=idx: self.change_keyboard_layout(x)) act.setCheckable(True) if selected_keymap == keymap[0]: self.change_keyboard_layout(idx) act.setChecked(True) keymap_group.addAction(act) keyboard_layout_menu.addAction(act) # check "QWERTY" if nothing else is selected if keymap_group.checkedAction() is None: keymap_group.actions()[0].setChecked(True) self.security_menu = self.menuBar().addMenu(tr("Menu", "Security")) self.security_menu.addAction(keyboard_unlock_act) self.security_menu.addAction(keyboard_lock_act) self.security_menu.addSeparator() self.security_menu.addAction(keyboard_reset_act) self.theme_menu = self.menuBar().addMenu(tr("Menu", "Theme")) theme_group = QActionGroup(self) selected_theme = self.get_theme() for name, _ in [("System", None)] + themes.themes: act = QAction(tr("MenuTheme", name), self) act.triggered.connect(lambda x, name=name: self.set_theme(name)) act.setCheckable(True) act.setChecked(selected_theme == name) theme_group.addAction(act) self.theme_menu.addAction(act) # check "System" if nothing else is selected if theme_group.checkedAction() is None: theme_group.actions()[0].setChecked(True) def on_layout_load(self): dialog = QFileDialog() dialog.setDefaultSuffix("vil") dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setNameFilters(["Vial layout (*.vil)"]) if dialog.exec_() == QDialog.Accepted: with open(dialog.selectedFiles()[0], "rb") as inf: data = inf.read() self.keymap_editor.restore_layout(data) self.rebuild() def on_layout_save(self): dialog = QFileDialog() dialog.setDefaultSuffix("vil") dialog.setAcceptMode(QFileDialog.AcceptSave) dialog.setNameFilters(["Vial layout (*.vil)"]) if dialog.exec_() == QDialog.Accepted: with open(dialog.selectedFiles()[0], "wb") as outf: outf.write(self.keymap_editor.save_layout()) def on_click_refresh(self): self.combobox_devices.clear() self.devices = find_vial_devices(self.via_stack_json, self.sideload_vid, self.sideload_pid) for dev in self.devices: self.combobox_devices.addItem(dev.title()) if self.devices: self.lbl_no_devices.hide() self.tabs.show() else: self.lbl_no_devices.show() self.tabs.hide() def on_device_selected(self): if self.current_device is not None: self.current_device.close() self.current_device = None idx = self.combobox_devices.currentIndex() if idx >= 0: self.current_device = self.devices[idx] if self.current_device is not None: if self.current_device.sideload: self.current_device.open(self.sideload_json) elif self.current_device.via_stack: self.current_device.open(self.via_stack_json["definitions"][ self.current_device.via_id]) else: self.current_device.open(None) if isinstance(self.current_device, VialKeyboard) \ and self.current_device.keyboard.keyboard_id in EXAMPLE_KEYBOARDS: QMessageBox.warning( self, "", "An example keyboard UID was detected.\n" "Please change your keyboard UID to be unique before you ship!" ) self.rebuild() self.refresh_tabs() def rebuild(self): # don't show "Security" menu for bootloader mode, as the bootloader is inherently insecure self.security_menu.menuAction().setVisible( isinstance(self.current_device, VialKeyboard)) # if unlock process was interrupted, we must finish it first if isinstance( self.current_device, VialKeyboard ) and self.current_device.keyboard.get_unlock_in_progress(): Unlocker.unlock(self.current_device.keyboard) self.current_device.keyboard.reload() for e in [ self.layout_editor, self.keymap_editor, self.firmware_flasher, self.macro_recorder, self.matrix_tester ]: e.rebuild(self.current_device) def refresh_tabs(self): self.tabs.clear() for container, lbl in self.editors: if not container.valid(): continue w = QWidget() w.setLayout(container) self.tabs.addTab(w, tr("MainWindow", lbl)) def load_via_stack_json(self): data = urlopen( "https://github.com/vial-kb/via-keymap-precompiled/raw/main/via_keyboard_stack.json" ) self.via_stack_json = json.load(data) # write to cache with open(os.path.join(self.cache_path, "via_keyboards.json"), "w") as cf: cf.write(json.dumps(self.via_stack_json, indent=2)) cf.close() def on_sideload_json(self): dialog = QFileDialog() dialog.setDefaultSuffix("json") dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setNameFilters(["VIA layout JSON (*.json)"]) if dialog.exec_() == QDialog.Accepted: with open(dialog.selectedFiles()[0], "rb") as inf: data = inf.read() self.sideload_json = json.loads(data) self.sideload_vid = int(self.sideload_json["vendorId"], 16) self.sideload_pid = int(self.sideload_json["productId"], 16) self.on_click_refresh() def on_load_dummy(self): dialog = QFileDialog() dialog.setDefaultSuffix("json") dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setNameFilters(["VIA layout JSON (*.json)"]) if dialog.exec_() == QDialog.Accepted: with open(dialog.selectedFiles()[0], "rb") as inf: data = inf.read() self.sideload_json = json.loads(data) self.sideload_vid = self.sideload_pid = 0 self.on_click_refresh() def lock_ui(self): self.tabs.setEnabled(False) self.combobox_devices.setEnabled(False) self.btn_refresh_devices.setEnabled(False) def unlock_ui(self): self.tabs.setEnabled(True) self.combobox_devices.setEnabled(True) self.btn_refresh_devices.setEnabled(True) def unlock_keyboard(self): if isinstance(self.current_device, VialKeyboard): Unlocker.unlock(self.current_device.keyboard) def lock_keyboard(self): if isinstance(self.current_device, VialKeyboard): self.current_device.keyboard.lock() def reboot_to_bootloader(self): if isinstance(self.current_device, VialKeyboard): Unlocker.unlock(self.current_device.keyboard) self.current_device.keyboard.reset() def change_keyboard_layout(self, index): self.settings.setValue("keymap", KEYMAPS[index][0]) self.keymap_editor.set_keymap_override(KEYMAPS[index][1]) def get_theme(self): return self.settings.value("theme", "Dark") def set_theme(self, theme): themes.set_theme(theme) self.settings.setValue("theme", theme) msg = QMessageBox() msg.setText( tr( "MainWindow", "In order to fully apply the theme you should restart the application." )) msg.exec_()
class TableWidget(QSplitter): def __init__(self): super(TableWidget, self).__init__() # vbox = QVBoxLayout(self) # vbox.setContentsMargins(0, 0, 0, 0) self._tabs = QTabWidget() self._tabs.setAutoFillBackground(True) p = self._tabs.palette() p.setColor(p.Window, QColor("white")) self._tabs.setPalette(p) self._other_tab = QTabWidget() self._other_tab.setAutoFillBackground(True) self._other_tab.setPalette(p) self.addWidget(self._tabs) self.addWidget(self._other_tab) self.setSizes([1, 1]) self._other_tab.hide() self.relations = {} # Stack self.stacked = QStackedWidget() self._tabs.addTab(self.stacked, "Workspace") self.stacked_result = QStackedWidget() self._tabs.addTab(self.stacked_result, self.tr("Resultados")) btn_split = QToolButton() btn_split.setToolTip(self.tr("Click para dividir la pantalla")) btn_split.setAutoRaise(True) btn_split.setIcon(QIcon(":img/split")) self._tabs.setCornerWidget(btn_split) btn_split.clicked.connect(self._split) btn_split = QToolButton() btn_split.setToolTip(self.tr("Click para juntar las pantallas")) btn_split.setAutoRaise(True) btn_split.setIcon(QIcon(":img/split")) btn_split.clicked.connect(self._unsplit) self._other_tab.setCornerWidget(btn_split) # self.setContextMenuPolicy(Qt.CustomContextMenu) # self.customContextMenuRequested.connect(self._show_menu) lateral_widget = Pireal.get_service("lateral_widget") lateral_widget.resultClicked.connect(self._on_result_list_clicked) lateral_widget.resultSelectionChanged.connect( lambda index: self.stacked_result.setCurrentIndex(index)) # lateral_widget.newRowsRequested.connect(self._insert_rows) def insert_rows(self, tuplas): current_view = self.current_table() if current_view is not None: model = current_view.model() for tupla in tuplas: model.insertRow(model.rowCount(), tupla) current_view.adjust_columns() def _on_result_list_clicked(self, index): self.stacked_result.setCurrentIndex(index) if not self._other_tab.isVisible(): self._tabs.setCurrentIndex(1) def _unsplit(self): self._other_tab.hide() result_widget = self._other_tab.widget(0) self._tabs.addTab(result_widget, self.tr("Resultados")) self._tabs.cornerWidget().show() def _split(self): result_widget = self._tabs.widget(1) self._other_tab.addTab(result_widget, self.tr("Resultados")) self._other_tab.show() self.setSizes([1, 1]) self._tabs.cornerWidget().hide() self.setOrientation(Qt.Horizontal) def _show_menu(self, position): menu = QMenu(self) if self.count() > 0: add_tuple_action = menu.addAction(self.tr("Agregar Tupla")) add_col_action = menu.addAction(self.tr("Add Column")) add_tuple_action.triggered.connect(self.add_tuple) add_col_action.triggered.connect(self.add_column) menu.addSeparator() add_relation_action = menu.addAction(self.tr("Create new Relation")) add_relation_action.triggered.connect(self.__new_relation) menu.exec_(self.mapToGlobal(position)) def __new_relation(self): central_service = Pireal.get_service("central") central_service.create_new_relation() def count(self): return self.stacked.count() def remove_table(self, index): widget = self.stacked.widget(index) self.stacked.removeWidget(widget) del widget def current_table(self): return self.stacked.currentWidget() def remove_relation(self, name): del self.relations[name] def add_relation(self, name, rela): if self.relations.get(name, None) is None: self.relations[name] = rela return True return False def add_table(self, rela, name, table): """ Add new table from New Relation Dialog """ self.add_relation(name, rela) self.stacked.addWidget(table) def add_tuple(self): current_view = self.current_table() if current_view is not None: model = current_view.model() model.insertRow(model.rowCount()) def add_column(self): current_view = self.current_table() if current_view is not None: model = current_view.model() model.insertColumn(model.columnCount()) def delete_tuple(self): current_view = self.current_table() if current_view is not None: model = current_view.model() selection = current_view.selectionModel() if selection.hasSelection(): selection = selection.selection() rows = set([index.row() for index in selection.indexes()]) rows = sorted(list(rows)) previous = -1 i = len(rows) - 1 while i >= 0: current = rows[i] if current != previous: model.removeRow(current) i -= 1 def delete_column(self): """ Elimina la/las columnas seleccionadas """ current_view = self.current_table() if current_view is not None: model = current_view.model() selection = current_view.selectionModel() if selection.hasSelection(): selection = selection.selection() columns = set( [index.column() for index in selection.indexes()]) columns = sorted(list(columns)) previous = -1 i = len(columns) - 1 while i >= 0: current = columns[i] if current != previous: model.removeColumn(current) i -= 1 def create_table(self, rela, editable=True): """ Se crea la vista y el modelo """ _view = view.View() _model = model.Model(rela) if not editable: _model.editable = False _view.setModel(_model) _view.setItemDelegate(delegate.Delegate()) _view.setHorizontalHeader(view.Header()) return _view
class PlotWindow(QWidget): def __init__(self, tab): super(PlotWindow, self).__init__() self.tab = tab self.allAxes = {} self.curveList = [] self.extraLines = [] self.layout = QHBoxLayout() self.graph_layout = QVBoxLayout() self.gbox_layout = QVBoxLayout() self.tabGBActor = QTabWidget() self.dateplot = DatePlot(self) self.customize = Customize(self) self.button_arrow = self.ButtonArrow() self.button_del_graph = self.ButtonDelete() self.gbox_layout.addWidget(self.dateplot) self.gbox_layout.addWidget(self.customize) self.gbox_layout.addWidget(self.tabGBActor) self.gbox_layout.addWidget(self.button_del_graph) self.layout.addLayout(self.graph_layout) self.layout.addWidget(self.button_arrow) self.layout.addLayout(self.gbox_layout) for widget in [self.dateplot, self.customize, self.tabGBActor]: widget.setMaximumWidth(400) self.setLayout(self.layout) @property def mainwindow(self): return self.tab.mainwindow @property def config(self): return self.dateplot.config @property def axes2curves(self): d = {ax: [] for ax in [None] + list(self.allAxes.values())} for curve in self.curveList: d[curve.getAxes()].append(curve) return d @property def line2Curve(self): return {curve.line: curve for curve in self.curveList} @property def axes2id(self): d = {ax: id for id, ax in self.allAxes.items()} d[None] = None return d def createGraph(self, custom): try: self.graph.close() self.graph_layout.removeWidget(self.graph) self.graph.deleteLater() except AttributeError: pass self.graph = Graph(self, custom) self.graph_layout.insertWidget(0, self.graph) def getAxes(self, newType, i=-1): for i, ax in self.allAxes.items(): try: curve = self.axes2curves[ax][0] if curve.type == newType: return ax except IndexError: return ax if i == 3: raise ValueError('No Axe available') return i + 1 def setAxes(self, allAxes): for idAxes, oldAxes in list(self.allAxes.items()): self.unsetLines(oldAxes, allAxes) self.allAxes.pop(idAxes, None) self.allAxes = allAxes def unsetLines(self, axes, newAxes): while axes.lines: line = axes.lines[0] axes.lines.remove(line) try: curve = self.line2Curve[line] curve.line = False if curve.getAxes() not in newAxes.values(): curve.setAxes(None) except KeyError: pass del line def addCurve(self, curveConf): new_curve = Curve(self, curveConf) axes = self.getAxes(new_curve.type) if isinstance(axes, int): idAxes = axes self.customize.allAxes[idAxes].checkbox.setChecked(2) axes = self.allAxes[idAxes] new_curve.setAxes(axes) self.appendCurve(new_curve) self.graph.plotCurves(new_curve) return new_curve def appendCurve(self, new_curve): self.curveList.append(new_curve) self.customize.appendRow(new_curve) def switchCurve(self, axeId, curve): ax = self.allAxes[axeId] if axeId is not None else None self.graph.switchCurve(ax, curve) def removeCurve(self, curve): self.curveList.remove(curve) self.graph.removeCurve(curve) try: checkbox = curve.checkbox checkbox.setCheckable(True) checkbox.setChecked(0) except RuntimeError: pass # Checkbox could have been already deleted def constructGroupbox(self, config): while self.tabGBActor.count(): widget = self.tabGBActor.widget(0) self.clearLayout(widget.layout()) self.tabGBActor.removeTab(0) widget.close() widget.deleteLater() sortedModule = self.sortCfg(config) for actorname in sorted(sortedModule): config = sortedModule[actorname] if config: t = TabActor(self, config) self.tabGBActor.addTab(t, actorname) def showhideConfig(self, button_arrow): if not self.tabGBActor.isHidden(): self.tabGBActor.hide() self.dateplot.hide() self.customize.hide() self.button_del_graph.hide() button_arrow.setIcon(self.mainwindow.icon_arrow_left) else: self.tabGBActor.show() self.button_del_graph.show() self.dateplot.show() self.customize.show() button_arrow.setIcon(self.mainwindow.icon_arrow_right) def ButtonDelete(self): button = QPushButton('Remove Graph') button.clicked.connect(partial(self.removeGraph, self.layout)) return button def ButtonArrow(self): button_arrow = QPushButton() button_arrow.setIcon(self.mainwindow.icon_arrow_right) button_arrow.clicked.connect(partial(self.showhideConfig, button_arrow)) button_arrow.setStyleSheet('border: 0px') return button_arrow def removeGraph(self, layout): self.clearLayout(layout) self.tab.removeGraph(self) def clearLayout(self, layout): if layout is not None: while layout.count(): item = layout.takeAt(0) widget = item.widget() if widget is not None: widget.deleteLater() else: self.clearLayout(item.layout()) def table2label(self, tablename, mergeAIT=False): for key, label in self.mainwindow.cuArms.items(): if key in tablename: return label if mergeAIT: return 'AIT' else: return tablename.split('__')[0].upper() def sortCfg(self, config): sortedDict = {} for dev in config: label = self.table2label(tablename=dev.tablename, mergeAIT=False) try: sortedDict[label].append(dev) except KeyError: sortedDict[label] = [dev] return sortedDict
class App(QMainWindow): resized = pyqtSignal() def __init__(self, width=1080, height=720): super().__init__() self.connectionStatus = False self.width = width self.height = height self.initUI() # self.initSignalsSlots() self.qsObj = None self.deviceName = "" self.serialPort = None self.currentTabMode = -1 self.sched = None def initUI(self): self.title = 'AutonomousFlight Configurator v1.0' self.left = 0 self.top = 0 # self.width = 1080 # self.height = 720 self.toolbarheight = 65 self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.centerWindow() self.bundle_dir = os.path.dirname(os.path.abspath(__file__)) self.initWidgets() self.setFocus() def centerWindow(self): frameGeo = self.frameGeometry() screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos()) centerPoint = QApplication.desktop().screenGeometry(screen).center() frameGeo.moveCenter(centerPoint) self.move(frameGeo.topLeft()) def initWidgets(self): # HeaderBar self.initHeaderWidget = InitHeaderWidget(self) self.initHeaderWidget.setGeometry(0, 0, self.width, 100) self.initHeaderWidget.show() self.initHeaderWidget.connectionStatusChangedSignal.connect(self.processInitConnection) # Init CoverPage self.coverPageWidget = CoverPageWidget(self) self.coverPageWidget.setGeometry(0, 100, self.width, self.height-100) self.coverPageWidget.show() # Show self.show() def initWorkingWidget(self): # Init StatusHeaderBar self.statusHeaderWidget = StatusHeaderWidget(self, self.qsObj) self.statusHeaderWidget.setGeometry(0, 0, self.width, 100) self.statusHeaderWidget.connectionStatusChangedSignal.connect(self.processStatusConnection) # self.statusHeaderWidget.hide() # Init InfoTabs self.infoTabsWidget = QTabWidget(self) self.infoTabsWidget.setGeometry(0, 100, self.width, self.height-130) # Vertical: 2 self.infoTabsWidget.setTabPosition(2) self.tabNameList = ["CLI", "Overview", "Calibration", "Configure", "ParameterSetting", "Mode", "Sensor", "Motor", "Topology", "Blackbox", "SerialTerminal"] self.tabObjectDict = {"CLI":CLIWidget(self), "Overview":OverviewInfoWidget(self, self.qsObj), "Calibration":CalibrationWidget(self, self.qsObj), "Configure":ConfigureWidget(self, self.qsObj), "ParameterSetting":ParameterSettingWidget(self, self.qsObj), "Mode":FlightModeWidget(self, self.qsObj), "Sensor":SensorWidget(self, self.qsObj), "Motor":MotorInfoWidget(self, self.qsObj), "Topology":TopologyWidget(self, self.qsObj), "Blackbox":BlackboxWidget(self), "SerialTerminal":SerialTerminalWidget(self)} for key,value in self.tabObjectDict.items(): self.infoTabsWidget.addTab(value, key) # self.infoTabsWidget.hide() self.infoTabsWidget.currentChanged.connect(self.setTabMode) # Init StatusBar self.statusBar = QStatusBar() # "Packet error:","I2C error:","Cycle Time:", # "CPU Load:","MSP Version:", "MSP Load:", # "MSP Roundtrip:","HW roundtrip:","Drop ratio:" self.statusBarTopicList = ["Cycle Time:", "I2C error:", "CPU Load:", "MSP Version:"] self.packetInfoLabel = QLabel(" | ".join(self.statusBarTopicList)) self.statusBar.addWidget(self.packetInfoLabel) self.setStatusBar(self.statusBar) # self.statusBar.hide() def initSignalsSlots(self): pass def processInitConnection(self): result = False try: # Start serial port self.startSerialPort() self.qsObj = QuadStates() self.mspHandle = MSPv1(self.serialPort, self.qsObj) result = self.mspHandle.preCheck() # Respond to reboot command from MSPv1 self.mspHandle.rebootSignal.connect(self.reboot) except: print("Fail to open serial port.") if result: self.connectionStatus = True self.debug() self.initWorkingWidget() # Send command to MSP class self.statusHeaderWidget.statusDataRequestSignal.connect(self.mspHandle.processHeaderDataRequest) self.tabObjectDict["CLI"].cliSignal.connect(self.mspHandle.cliCommandSwitch) self.tabObjectDict["Overview"].overviewInfoSignal.connect(self.mspHandle.overviewInfoResponse) self.tabObjectDict["Mode"].flightmodeSaveSignal.connect(self.mspHandle.processModeRangesSave) self.tabObjectDict["Configure"].configureSaveSignal.connect(self.mspHandle.processConfigureSave) self.tabObjectDict["ParameterSetting"].parameterSaveSignal.connect(self.mspHandle.processParameterSettingSave) self.tabObjectDict["Calibration"].accCalibrateSignal.connect(self.mspHandle.processAccCalibrationRequest) self.tabObjectDict["Calibration"].magCalibrateSignal.connect(self.mspHandle.processMagCalibrationRequest) self.tabObjectDict["Calibration"].calibrationSaveSignal.connect(self.mspHandle.processCalibrationSave) self.tabObjectDict["Sensor"].sensorDataRequestSignal.connect(self.mspHandle.processSensorDataRequest) self.tabObjectDict["Motor"].motorDataRequestSignal.connect(self.mspHandle.processMotorDataRequest) self.tabObjectDict["Mode"].modeRCDataRequestSignal.connect(self.mspHandle.processModeRCDataRequest) self.tabObjectDict["Topology"].topologySaveSignal.connect(self.mspHandle.processTopologySave) self.tabObjectDict["SerialTerminal"].serTerSignal.connect(self.mspHandle.processSerialTerminalRequest) # MSP data changed will raise this signal to update labels in UI page self.mspHandle.headerDataUpdateSignal.connect(self.headerPageUpdate) self.mspHandle.cliFeedbackSignal.connect(self.tabObjectDict["CLI"].processFeedback) self.mspHandle.calibrationFeedbackSignal.connect(self.tabObjectDict["Calibration"].processFeedback) self.mspHandle.overviewDataUpdateSignal.connect(self.overviewPageUpdate) self.mspHandle.sensorDataUpdateSignal.connect(self.sensorPageUpdate) self.mspHandle.motorDataUpdateSignal.connect(self.motorPageUpdate) self.mspHandle.modeRCDataUpdateSignal.connect(self.flightmodePageRCUpdate) self.mspHandle.serTerFeedbackSignal.connect(self.tabObjectDict["SerialTerminal"].processFeedback) # Change UI self.initHeaderWidget.hide() self.coverPageWidget.hide() self.statusHeaderWidget.show() self.infoTabsWidget.show() self.infoTabsWidget.setCurrentIndex(0) self.setTabMode(0) self.statusBar.show() # Start StatusHeader Timer self.statusHeaderWidget.start() def processStatusConnection(self): self.connectionStatus = False # # self.checkSchedulerShutdown() self.setTabMode(0) self.statusHeaderWidget.stop() # End serial port self.closeSerialPort() self.qsObj = None # Change UI self.statusHeaderWidget.hide() self.infoTabsWidget.hide() self.statusBar.hide() self.initHeaderWidget.show() self.coverPageWidget.show() def keyPressEvent(self, event): if self.currentTabMode == 0: self.tabObjectDict["CLI"].keyPressed(event) def debug(self): print("---Debug---") # print(self.qsObj.msp_activeboxes) # print(self.qsObj.msp_boxids) # print(len(self.qsObj.msp_boxids)) # print(self.qsObj.msp_boxnames) # print(len(self.qsObj.msp_boxnames)) # print(self.qsObj.msp_mode_ranges) # print(len(self.qsObj.msp_mode_ranges)) print("---Debug---") pass # Process reboot def reboot(self): # Step 1: Close current connection self.processStatusConnection() # Step 2: Wait for 0.3 seconds self.waitTimer = QTimer() self.waitTimer.setInterval(300) self.waitTimer.setSingleShot(True) # Step 3: Reconnect self.waitTimer.timeout.connect(self.processInitConnection) self.waitTimer.start(300) # Page index # Change corresponding index if the tabObjectDict is changed. def setTabMode(self, index): if self.currentTabMode != index: if index == self.tabNameList.index("CLI"): # Stop header widget update self.statusHeaderWidget.stop() elif self.currentTabMode == self.tabNameList.index("CLI"): # Resume header widget update self.statusHeaderWidget.start() if index == self.tabNameList.index("Overview"): # Overview Page self.tabObjectDict["Overview"].start() elif self.currentTabMode == self.tabNameList.index("Overview"): self.tabObjectDict["Overview"].stop() if index == self.tabNameList.index("Calibration"): # Calibration self.calibrationPageUpdate() # Mode if index == self.tabNameList.index("Mode"): self.flightmodePageUpdate() self.tabObjectDict["Mode"].start() elif self.currentTabMode == self.tabNameList.index("Mode"): self.tabObjectDict["Mode"].stop() # Configure if index == self.tabNameList.index("Configure"): # Configure self.configurePageUpdate() if index == self.tabNameList.index("ParameterSetting"): # Parameter Setting self.parameterSettingPageUpdate() if index == self.tabNameList.index("Sensor"): # Sensor self.tabObjectDict["Sensor"].start() elif self.currentTabMode == self.tabNameList.index("Sensor"): self.tabObjectDict["Sensor"].stop() if index == self.tabNameList.index("Motor"): # Motor self.tabObjectDict["Motor"].start() elif self.currentTabMode == self.tabNameList.index("Motor"): self.tabObjectDict["Motor"].stop() # Topology if index == self.tabNameList.index("Topology"): # Topology self.topologyPageUpdate() if index == self.tabNameList.index("Blackbox"): # Blackbox pass if index == self.tabNameList.index("SerialTerminal"): # Serial Terminal # Stop header widget update self.statusHeaderWidget.stop() self.tabObjectDict["SerialTerminal"].start() elif self.currentTabMode == self.tabNameList.index("SerialTerminal"): self.tabObjectDict["SerialTerminal"].stop() # Resume header widget update self.statusHeaderWidget.start() self.currentTabMode = index def startSerialPort(self): self.deviceName = self.initHeaderWidget.connectionMethodComboBox.currentText() self.serialPort = SerialCommunication(self.deviceName) def closeSerialPort(self): self.serialPort.stopDevice() self.serialPort = None def headerPageUpdate(self, ind): if ind == 0: self.statusHeaderWidget.updateMMSV() elif ind == 1: self.statusHeaderWidget.updateSensorStatus() def overviewPageUpdate(self, ind): if ind == 0: self.tabObjectDict["Overview"].updateAttitudeLabels() elif ind == 1: self.tabObjectDict["Overview"].updateArmingFlagLabels() elif ind == 2: self.tabObjectDict["Overview"].updateBatteryLabels() elif ind == 3: self.tabObjectDict["Overview"].updateCommunicationLabels() elif ind == 4: self.tabObjectDict["Overview"].updateGPSLabels() # # Update header sensor lights. # self.statusHeaderWidget.update(self.qsObj.msp_sensor_status) # Update status bar self.statusBarUpdate() def statusBarUpdate(self): self.statusBarTopicList = ["Cycle Time:", "I2C Error:", "CPU Load:", "MSP Version:"] self.statusBarValueDict = {} for field in self.statusBarTopicList: data = None if field == "Cycle Time:": data = self.qsObj.msp_status_ex['cycleTime'] elif field == "I2C Error:": data = self.qsObj.msp_status_ex['i2cError'] elif field == "CPU Load:": data = self.qsObj.msp_status_ex['averageSystemLoadPercent'] elif field == "MSP Version:": data = "1" else: pass self.statusBarValueDict[field] = str(data) labelString = "| " for key,value in self.statusBarValueDict.items(): labelString = labelString + key + value + " | " self.packetInfoLabel.setText(labelString) def sensorPageUpdate(self, ind): if ind == 0: self.tabObjectDict["Sensor"].updateACCPlot() self.tabObjectDict["Sensor"].updateGYROPlot() self.tabObjectDict["Sensor"].updateMAGPlot() elif ind == 1: self.tabObjectDict["Sensor"].updateBAROPlot() elif ind == 2: self.tabObjectDict["Sensor"].updateRangeFinderPlot() def motorPageUpdate(self, ind): if ind == 0: self.tabObjectDict["Motor"].updateMotorValues() def flightmodePageRCUpdate(self, ind): if ind == 0: self.tabObjectDict["Mode"].updateCurrentValueLabels() def flightmodePageUpdate(self): self.tabObjectDict["Mode"].setRanges() def parameterSettingPageUpdate(self): self.mspHandle.processParameterSettingCheck() self.tabObjectDict['ParameterSetting'].setValues() def configurePageUpdate(self): self.mspHandle.processConfigureCheck() self.tabObjectDict['Configure'].setValues() def calibrationPageUpdate(self): self.mspHandle.processCalibrationCheck() self.tabObjectDict['Calibration'].setValues() def topologyPageUpdate(self): self.mspHandle.processTopologyCheck() self.tabObjectDict['Topology'].setValues()
class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.setWindowTitle("TFM - Inversión Bolsa") self.file = "" self.area = QPlainTextEdit() self.lineaFichero = QLineEdit() self.validacion = "" layout = QGridLayout() self.createlayoutMain(layout) self.window = QWidget() self.window.setLayout(layout) self.window.show() self.window.setFixedSize(self.window.size()) def createlayoutMain(self, layout): #Icono label = QLabel("Ayuda Broker") label.setFont(QFont("Helvetica", 30)) layout.addWidget(label, 0, 5) #Dialogo Carga Fichero lineaFichero = QLineEdit() lineaFichero.setReadOnly(True) self.lineaFichero = lineaFichero botonFile = QPushButton("Cargar Fichero") botonFile.clicked.connect(self.filedialog) layout.addWidget(lineaFichero, 1, 0, 1, 12) layout.addWidget(botonFile, 1, 12) #Boton ejecutar algoritmo botonMain = QPushButton("Ejecutar Algoritmo") botonMain.clicked.connect(self.ejecuta_algoritmo) layout.addWidget(botonMain, 2, 0) #Cuadro de logs oculto por defecto logarea = QPlainTextEdit() logarea.setReadOnly(True) logarea.setVisible(False) self.area = logarea layout.addWidget(logarea, 3, 0, 3, 18) #Tabs self.tabs = QTabWidget() self.tab1 = QWidget() self.tab2 = QWidget() self.tab3 = QWidget() self.tabs.addTab(self.tab1, "Gráfica Red Neuronal Entrenada") self.tabs.addTab(self.tab2, "Datos útiles") self.tabs.addTab(self.tab3, "Predecir otro valor") #Tab Gráfica self.tab1.layout = QVBoxLayout() self.labelGraph = QLabel(self) self.tab1.layout.addWidget(self.labelGraph) self.tab1.setLayout(self.tab1.layout) #Tab Datos Útiles self.tab2.layout = QGridLayout() self.tab2.setLayout(self.tab2.layout) self.font = QFont("Helvetica", 15) self.font.setBold(True) self.lTendenciaActual = QLabel("Tendencia Actual:") self.lTendenciaActual.setFont(self.font) self.tab2.layout.addWidget(self.lTendenciaActual, 1, 1) self.lAscendente = QLabel("Ascendente:") self.lAscendente.setFont(self.font) self.lDescendente = QLabel("Descendente:") self.lDescendente.setFont(self.font) self.lMayorNumDiasSubiendo = QLabel("Mayor nº de días subiendo:") self.lMayorNumDiasSubiendo.setFont(self.font) self.tab2.layout.addWidget(self.lMayorNumDiasSubiendo, 5, 1) self.lMayorNumDiasBajando = QLabel("Mayor nº de días bajando:") self.lMayorNumDiasBajando.setFont(self.font) self.tab2.layout.addWidget(self.lMayorNumDiasBajando, 7, 1) self.lPrecioMinimo = QLabel("Precio Mínimo:") self.lPrecioMinimo.setFont(self.font) self.tab2.layout.addWidget(self.lPrecioMinimo, 9, 1) self.lPrecioMaximo = QLabel("Precio Máximo:") self.lPrecioMaximo.setFont(self.font) self.tab2.layout.addWidget(self.lPrecioMaximo, 11, 1) fontvalor = QFont("Helvetica", 15) self.lTendenciaActual = QLabel("") self.lTendenciaActual.setFont(fontvalor) self.tab2.layout.addWidget(self.lTendenciaActual, 1, 2) self.lAscendenteDescendente = QLabel("") self.lAscendenteDescendente.setFont(fontvalor) self.tab2.layout.addWidget(self.lAscendenteDescendente, 3, 2) self.lMayorNumDiasBajando = QLabel("") self.lMayorNumDiasBajando.setFont(fontvalor) self.tab2.layout.addWidget(self.lMayorNumDiasBajando, 5, 2) self.lMayorNumDiasSubiendo = QLabel("") self.lMayorNumDiasSubiendo.setFont(fontvalor) self.tab2.layout.addWidget(self.lMayorNumDiasSubiendo, 7, 2) self.lPrecioMinimo = QLabel("") self.lPrecioMinimo.setFont(fontvalor) self.tab2.layout.addWidget(self.lPrecioMinimo, 9, 2) self.lPrecioMaximo = QLabel("") self.lPrecioMaximo.setFont(fontvalor) self.tab2.layout.addWidget(self.lPrecioMaximo, 11, 2) self.lprediccion = QLabel("") self.tab2.layout.addWidget(self.lprediccion, 13, 1, 1, 2) self.tab2.layout.setRowStretch(0, 1) self.tab2.layout.setRowStretch(2, 1) self.tab2.layout.setRowStretch(4, 1) self.tab2.layout.setRowStretch(6, 1) self.tab2.layout.setRowStretch(8, 1) self.tab2.layout.setRowStretch(10, 1) self.tab2.layout.setRowStretch(12, 1) self.tab2.layout.setColumnStretch(0, 1) self.tab2.layout.setColumnStretch(3, 1) #Tab otro valor self.tab3.layout = QGridLayout() self.tab3.setLayout(self.tab3.layout) self.precio1 = QLineEdit() self.precio2 = QLineEdit() self.precio3 = QLineEdit() self.precio4 = QLineEdit() self.precio5 = QLineEdit() self.precio6 = QLineEdit() self.precio7 = QLineEdit() self.precio8 = QLineEdit() self.lprecio1 = QLabel("Día 1: ") fontN = self.lprecio1.font() fontN.setBold(True) self.lprecio1.setFont(fontN) self.tab3.layout.addWidget(self.lprecio1, 3, 1) self.lprecio2 = QLabel("Día 2: ") self.lprecio2.setFont(fontN) self.tab3.layout.addWidget(self.lprecio2, 3, 3) self.lprecio3 = QLabel("Día 3: ") self.lprecio3.setFont(fontN) self.tab3.layout.addWidget(self.lprecio3, 4, 1) self.lprecio4 = QLabel("Día 4: ") self.lprecio4.setFont(fontN) self.tab3.layout.addWidget(self.lprecio4, 4, 3) self.lprecio5 = QLabel("Día 5: ") self.lprecio5.setFont(fontN) self.tab3.layout.addWidget(self.lprecio5, 5, 1) self.lprecio6 = QLabel("Día 6: ") self.lprecio6.setFont(fontN) self.tab3.layout.addWidget(self.lprecio6, 5, 3) self.lprecio7 = QLabel("Día 7: ") self.lprecio7.setFont(fontN) self.tab3.layout.addWidget(self.lprecio7, 6, 1) self.lprecio8 = QLabel("Día 8: ") self.lprecio8.setFont(fontN) self.tab3.layout.addWidget(self.lprecio8, 6, 3) self.tab3.layout.setRowStretch(0, 1) self.tab3.layout.setRowStretch(1, 1) self.tab3.layout.setRowStretch(7, 1) self.tab3.layout.setRowStretch(9, 1) self.tab3.layout.setRowStretch(11, 1) self.tab3.layout.setColumnStretch(0, 1) self.tab3.layout.setColumnStretch(5, 1) self.ltituloTab3 = QLabel( "Para predecir otro precio, es necesario indicar los precios de los 8 días anteriores" ) self.tab3.layout.addWidget(self.ltituloTab3, 1, 1, 1, 4) self.tab3.layout.addWidget(self.precio1, 3, 2) self.tab3.layout.addWidget(self.precio2, 3, 4) self.tab3.layout.addWidget(self.precio3, 4, 2) self.tab3.layout.addWidget(self.precio4, 4, 4) self.tab3.layout.addWidget(self.precio5, 5, 2) self.tab3.layout.addWidget(self.precio6, 5, 4) self.tab3.layout.addWidget(self.precio7, 6, 2) self.tab3.layout.addWidget(self.precio8, 6, 4) self.botonNuevoValor = QPushButton("Predecir Precio") self.botonNuevoValor.clicked.connect(self.predecirNuevoValor) self.tab3.layout.addWidget(self.botonNuevoValor, 8, 3) self.lnuevoPrecioTab3 = QLabel("") self.tab3.layout.addWidget(self.lnuevoPrecioTab3, 10, 1, 1, 4) layout.addWidget(self.tabs, 6, 0, 2, 18) self.tabs.setVisible(False) def predecirNuevoValor(self): if not ((self.precio1.text().strip() == "") or (self.precio2.text().strip() == "") or (self.precio3.text().strip() == "") or (self.precio4.text().strip() == "") or (self.precio5.text().strip() == "") or (self.precio6.text().strip() == "") or (self.precio7.text().strip() == "") or (self.precio8.text().strip() == "")): prediccion = np.asarray([ self.precio1.text().strip(), self.precio2.text().strip(), self.precio3.text().strip(), self.precio4.text().strip(), self.precio5.text().strip(), self.precio6.text().strip(), self.precio7.text().strip(), self.precio8.text().strip() ]) entradaPrediccion = [] entradaPrediccion.append(prediccion) try: res = self.modelo.predict([entradaPrediccion]) self.lnuevoPrecioTab3.setText("El próximo precio es: " + str(res[0][0])) except Exception as p: self.area.insertPlainText( "Algo fue mal durante la ejecución del algoritmo, revisa los datos de entrada...\n" ) self.area.repaint() print(str(p)) else: self.area.insertPlainText( "Todos los campos deben estar rellenos...\n") self.area.repaint() def filedialog(self): # Cargar Archivo fileName, _ = QtWidgets.QFileDialog.getOpenFileName( self, 'Single File', QtCore.QDir.rootPath(), '*.csv') if fileName: self.file = fileName self.lineaFichero.setText(self.file) self.lineaFichero.repaint() def initAlgoritmo(self): self.area.setPlainText("") self.area.repaint() self.tabs.hide() plt.cla() if os.path.exists("grafico.jpg"): os.remove("grafico.jpg") def ejecuta_algoritmo(self): self.area.show() #Limpiamos las areas de logs, gráfica y datos self.initAlgoritmo() if Utils.rutaFicheroValido(self): try: # Leemos el CSV completo que contiene los datos self.datos_csv = pd.read_csv(self.file, delimiter=",", index_col=0, parse_dates=["date"]) if Utils.validaExcel(self, self.datos_csv): self.area.insertPlainText( "El Formato del excel es correcto...\n") self.area.repaint() # Creamos la Red Neuronal # Tomamos todos los datos y los dividimos en un 80% para entrenat y 20% para validar # year2017 = datos_csv.close['2017-01-01':'2017-12-31'] year = self.datos_csv.precio # count2017 = len(datos_csv.close['2017-01-01':'2017-12-31']) count = len(self.datos_csv.precio) numEntradas = 8 numDatosEntrenamiento = round(count * 0.8) numDatosValidacion = round(count * 0.2) self.area.insertPlainText( "El número total de datos son: " + str(count) + "\n") self.area.insertPlainText( "Los datos de entrenamiento son: " + str(numDatosEntrenamiento) + "\n") self.area.insertPlainText("Los datos de validacion son: " + str(numDatosValidacion) + "\n") self.area.repaint() dfEntrenamiento = year[:numDatosEntrenamiento] dfValidacion = year[numDatosEntrenamiento:] print( " Entrenamiento: Elementos sobrantes del array será: " + str(numDatosEntrenamiento % numEntradas) + " y se usaran " + str(round(numDatosEntrenamiento / numEntradas))) print(" Validacion: Elementos sobrantes del array será: " + str(numDatosValidacion % numEntradas) + " y se usaran " + str(round(numDatosValidacion / numEntradas))) listaEntrenamiento = Utils.listaTransformada( numEntradas, numDatosEntrenamiento, dfEntrenamiento) listaValidacion = Utils.listaTransformada( numEntradas, numDatosValidacion, dfValidacion) print(str(listaEntrenamiento[0][:2])) print(str(listaEntrenamiento[1][:2])) try: self.modelo = Utils.modeloRedNeuronal(numEntradas) self.historic = self.modelo.fit( listaEntrenamiento[0], listaEntrenamiento[1], epochs=40, validation_data=(listaValidacion[0], listaValidacion[1]), batch_size=numEntradas) self.area.insertPlainText( "FIN: La red neuronal ha sido entrenada\n") self.area.repaint() # Generamos la gráfica y rellenamos la tab 1 results = self.modelo.predict(listaValidacion[0]) if len(results) > 100: plt.scatter(range(len(listaValidacion[1][:100])), (listaValidacion[1])[:100], c='g') plt.scatter(range(len(results[:100])), results[:100], c='r') else: plt.scatter(range(len(listaValidacion[1])), listaValidacion[1], c='g') plt.scatter(range(len(results)), results, c='r') plt.xlabel("Punto Evaluado") plt.ylabel("Precio") plt.title('Red Neuronal entrenada vs realidad') score = self.modelo.evaluate(listaEntrenamiento[0], listaEntrenamiento[1], batch_size=128) print(str(self.modelo.metrics_names)) print("La efectividad ha sido del: " + str(score)) red_patch = mpatches.Patch(color='red', label='Precios predichos') green_patch = mpatches.Patch(color='green', label='Precios reales') plt.legend(handles=[red_patch, green_patch]) plt.savefig('grafico.jpg') pixmap = QPixmap('grafico.jpg') self.labelGraph.setPixmap(pixmap) self.tabs.setVisible(True) # Generamos los datos útiles y rellenamos la tab 2 Utils.dataExcel(self, self.datos_csv) fontvalor = QFont("Helvetica", 15) self.lTendenciaActual.setText(str( self.tendenciaActual)) self.lMayorNumDiasBajando.setText( str(self.mayorTendenciaDescentente)) self.lMayorNumDiasSubiendo.setText( str(self.mayorTendenciaAscendente)) self.lPrecioMinimo.setText(str(self.precioMinimo)) self.lPrecioMaximo.setText(str(self.precioMaximo)) if self.tendenciaActual == "Ascendente": self.tab2.layout.addWidget(self.lAscendente, 3, 1) self.lAscendenteDescendente.setText( str(self.tendenciaAscendente)) else: self.tab2.layout.addWidget(self.lDescendente, 3, 1) self.lAscendenteDescendente.setText( str(self.tendenciaDescentente)) prediccionArray = np.asarray( self.datos_csv.tail(8).precio.values.tolist()) entradaPrediccion = [] entradaPrediccion.append(prediccionArray) res = self.modelo.predict([entradaPrediccion]) self.lprediccion.setText( "La red Neuronal predice que el próximo precio será: " + str(res[0][0])) except Exception as e: self.area.insertPlainText( "Hubo algun error durante la ejecución del algritmo\n" ) self.area.repaint() print(str(e)) else: self.area.insertPlainText(self.validacion) self.area.repaint() except Exception as b: self.area.insertPlainText( "Algo fue mal durante la lectura del CSV, revisa que sea correcto\n" ) self.area.repaint() print(str(b)) else: self.area.insertPlainText(self.validacion) self.area.repaint()
class ManifestWidget(TritonWidget): def __init__(self, base, drive): TritonWidget.__init__(self, base) self.drive = drive self.setWindowTitle('NextcloudRestore') self.setBackgroundColor(self, Qt.white) self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.menuBar = QMenuBar() fileMenu = self.menuBar.addMenu('File') self.label = QLabel('Searching for manifests...') self.label.setAlignment(Qt.AlignCenter) self.label.setFont(QFont('Sans Serif', 20)) self.tabs = QTabWidget() self.tabs.setMinimumSize(300, 300) self.tabs.setMaximumSize(300, 300) self.tabs.hide() self.layout.setAlignment(Qt.AlignCenter) self.layout.addWidget(self.menuBar) self.layout.addWidget(self.label) self.layout.addWidget(self.tabs) self.setLayout(self.layout) self.resizeAndCenter() self.show() self.retriever = ManifestRetriever(self.drive) self.retriever.signal.connect(self.gotManifests) self.retriever.start() self.downloader = None def gotManifests(self, manifests): self.label.setText('Choose the manifest to recover:') for folder in sorted(manifests.keys()): files = manifests[folder] tab = ManifestTab(self, folder, files) self.tabs.addTab(tab, folder) self.tabs.show() self.resizeAndCenter() def downloadManifest(self, name, manifest): destination = self.base.tmp.getFile(name) if os.path.exists(destination): self.downloadedManifest(name, manifest, destination) return self.label.setText('Downloading manifest...') self.tabs.setEnabled(False) self.downloader = ManifestDownloader(name, manifest, destination) self.downloader.signal.connect(self.downloadedManifest) self.downloader.start() def downloadedManifest(self, name, manifest, destination): self.label.setText('Manifest downloaded.') self.tabs.setEnabled(True)
def hide ( self ): QTabWidget.hide ( self )
class MainWindow(QMainWindow): def __init__(self, appctx): super().__init__() self.appctx = appctx self.settings = QSettings("Vial", "Vial") if self.settings.value("size", None) and self.settings.value( "pos", None): self.resize(self.settings.value("size")) self.move(self.settings.value("pos")) else: self.resize(WINDOW_WIDTH, WINDOW_HEIGHT) themes.set_theme(self.get_theme()) self.combobox_devices = QComboBox() self.combobox_devices.currentIndexChanged.connect( self.on_device_selected) self.btn_refresh_devices = QToolButton() self.btn_refresh_devices.setToolButtonStyle(Qt.ToolButtonTextOnly) self.btn_refresh_devices.setText(tr("MainWindow", "Refresh")) self.btn_refresh_devices.clicked.connect(self.on_click_refresh) layout_combobox = QHBoxLayout() layout_combobox.addWidget(self.combobox_devices) layout_combobox.addWidget(self.btn_refresh_devices) self.layout_editor = LayoutEditor() self.keymap_editor = KeymapEditor(self.layout_editor) self.firmware_flasher = FirmwareFlasher(self) self.macro_recorder = MacroRecorder() self.tap_dance = TapDance() self.combos = Combos() QmkSettings.initialize(appctx) self.qmk_settings = QmkSettings() self.matrix_tester = MatrixTest(self.layout_editor) self.rgb_configurator = RGBConfigurator() self.editors = [(self.keymap_editor, "Keymap"), (self.layout_editor, "Layout"), (self.macro_recorder, "Macros"), (self.rgb_configurator, "Lighting"), (self.tap_dance, "Tap Dance"), (self.combos, "Combos"), (self.qmk_settings, "QMK Settings"), (self.matrix_tester, "Matrix tester"), (self.firmware_flasher, "Firmware updater")] Unlocker.global_layout_editor = self.layout_editor self.current_tab = None self.tabs = QTabWidget() self.tabs.currentChanged.connect(self.on_tab_changed) self.refresh_tabs() no_devices = 'No devices detected. Connect a Vial-compatible device and press "Refresh"<br>' \ 'or select "File" → "Download VIA definitions" in order to enable support for VIA keyboards.' if sys.platform.startswith("linux"): no_devices += '<br><br>On Linux you need to set up a custom udev rule for keyboards to be detected. ' \ 'Follow the instructions linked below:<br>' \ '<a href="https://get.vial.today/manual/linux-udev.html">https://get.vial.today/manual/linux-udev.html</a>' self.lbl_no_devices = QLabel(tr("MainWindow", no_devices)) self.lbl_no_devices.setTextFormat(Qt.RichText) self.lbl_no_devices.setAlignment(Qt.AlignCenter) layout = QVBoxLayout() layout.addLayout(layout_combobox) layout.addWidget(self.tabs) layout.addWidget(self.lbl_no_devices) layout.setAlignment(self.lbl_no_devices, Qt.AlignHCenter) self.tray_keycodes = TabbedKeycodes() self.tray_keycodes.make_tray() layout.addWidget(self.tray_keycodes) self.tray_keycodes.hide() w = QWidget() w.setLayout(layout) self.setCentralWidget(w) self.init_menu() self.autorefresh = Autorefresh() self.autorefresh.devices_updated.connect(self.on_devices_updated) # cache for via definition files self.cache_path = QStandardPaths.writableLocation( QStandardPaths.CacheLocation) if not os.path.exists(self.cache_path): os.makedirs(self.cache_path) # check if the via defitions already exist if os.path.isfile(os.path.join(self.cache_path, "via_keyboards.json")): with open(os.path.join(self.cache_path, "via_keyboards.json")) as vf: data = vf.read() try: self.autorefresh.load_via_stack(data) except JSONDecodeError as e: # the saved file is invalid - just ignore this logging.warning( "Failed to parse stored via_keyboards.json: {}".format(e)) # make sure initial state is valid self.on_click_refresh() def init_menu(self): layout_load_act = QAction(tr("MenuFile", "Load saved layout..."), self) layout_load_act.setShortcut("Ctrl+O") layout_load_act.triggered.connect(self.on_layout_load) layout_save_act = QAction(tr("MenuFile", "Save current layout..."), self) layout_save_act.setShortcut("Ctrl+S") layout_save_act.triggered.connect(self.on_layout_save) sideload_json_act = QAction(tr("MenuFile", "Sideload VIA JSON..."), self) sideload_json_act.triggered.connect(self.on_sideload_json) download_via_stack_act = QAction( tr("MenuFile", "Download VIA definitions"), self) download_via_stack_act.triggered.connect(self.load_via_stack_json) load_dummy_act = QAction(tr("MenuFile", "Load dummy JSON..."), self) load_dummy_act.triggered.connect(self.on_load_dummy) exit_act = QAction(tr("MenuFile", "Exit"), self) exit_act.setShortcut("Ctrl+Q") exit_act.triggered.connect(qApp.exit) file_menu = self.menuBar().addMenu(tr("Menu", "File")) file_menu.addAction(layout_load_act) file_menu.addAction(layout_save_act) file_menu.addSeparator() file_menu.addAction(sideload_json_act) file_menu.addAction(download_via_stack_act) file_menu.addAction(load_dummy_act) file_menu.addSeparator() file_menu.addAction(exit_act) keyboard_unlock_act = QAction(tr("MenuSecurity", "Unlock"), self) keyboard_unlock_act.triggered.connect(self.unlock_keyboard) keyboard_lock_act = QAction(tr("MenuSecurity", "Lock"), self) keyboard_lock_act.triggered.connect(self.lock_keyboard) keyboard_reset_act = QAction( tr("MenuSecurity", "Reboot to bootloader"), self) keyboard_reset_act.triggered.connect(self.reboot_to_bootloader) keyboard_layout_menu = self.menuBar().addMenu( tr("Menu", "Keyboard layout")) keymap_group = QActionGroup(self) selected_keymap = self.settings.value("keymap") for idx, keymap in enumerate(KEYMAPS): act = QAction(tr("KeyboardLayout", keymap[0]), self) act.triggered.connect( lambda checked, x=idx: self.change_keyboard_layout(x)) act.setCheckable(True) if selected_keymap == keymap[0]: self.change_keyboard_layout(idx) act.setChecked(True) keymap_group.addAction(act) keyboard_layout_menu.addAction(act) # check "QWERTY" if nothing else is selected if keymap_group.checkedAction() is None: keymap_group.actions()[0].setChecked(True) self.security_menu = self.menuBar().addMenu(tr("Menu", "Security")) self.security_menu.addAction(keyboard_unlock_act) self.security_menu.addAction(keyboard_lock_act) self.security_menu.addSeparator() self.security_menu.addAction(keyboard_reset_act) self.theme_menu = self.menuBar().addMenu(tr("Menu", "Theme")) theme_group = QActionGroup(self) selected_theme = self.get_theme() for name, _ in [("System", None)] + themes.themes: act = QAction(tr("MenuTheme", name), self) act.triggered.connect(lambda x, name=name: self.set_theme(name)) act.setCheckable(True) act.setChecked(selected_theme == name) theme_group.addAction(act) self.theme_menu.addAction(act) # check "System" if nothing else is selected if theme_group.checkedAction() is None: theme_group.actions()[0].setChecked(True) about_vial_act = QAction(tr("MenuAbout", "About Vial..."), self) about_vial_act.triggered.connect(self.about_vial) self.about_menu = self.menuBar().addMenu(tr("Menu", "About")) self.about_menu.addAction(about_vial_act) def on_layout_load(self): dialog = QFileDialog() dialog.setDefaultSuffix("vil") dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setNameFilters(["Vial layout (*.vil)"]) if dialog.exec_() == QDialog.Accepted: with open(dialog.selectedFiles()[0], "rb") as inf: data = inf.read() self.keymap_editor.restore_layout(data) self.rebuild() def on_layout_save(self): dialog = QFileDialog() dialog.setDefaultSuffix("vil") dialog.setAcceptMode(QFileDialog.AcceptSave) dialog.setNameFilters(["Vial layout (*.vil)"]) if dialog.exec_() == QDialog.Accepted: with open(dialog.selectedFiles()[0], "wb") as outf: outf.write(self.keymap_editor.save_layout()) def on_click_refresh(self): # we don't do check_protocol here either because if the matrix test tab is active, # that ends up corrupting usb hid packets self.autorefresh.update(check_protocol=False) def on_devices_updated(self, devices, hard_refresh): self.combobox_devices.blockSignals(True) self.combobox_devices.clear() for dev in devices: self.combobox_devices.addItem(dev.title()) if self.autorefresh.current_device and dev.desc[ "path"] == self.autorefresh.current_device.desc["path"]: self.combobox_devices.setCurrentIndex( self.combobox_devices.count() - 1) self.combobox_devices.blockSignals(False) if devices: self.lbl_no_devices.hide() self.tabs.show() else: self.lbl_no_devices.show() self.tabs.hide() if hard_refresh: self.on_device_selected() def on_device_selected(self): try: self.autorefresh.select_device( self.combobox_devices.currentIndex()) except ProtocolError: QMessageBox.warning( self, "", "Unsupported protocol version!\n" "Please download latest Vial from https://get.vial.today/") if isinstance(self.autorefresh.current_device, VialKeyboard) \ and self.autorefresh.current_device.keyboard.keyboard_id in EXAMPLE_KEYBOARDS: QMessageBox.warning( self, "", "An example keyboard UID was detected.\n" "Please change your keyboard UID to be unique before you ship!" ) self.rebuild() self.refresh_tabs() def rebuild(self): # don't show "Security" menu for bootloader mode, as the bootloader is inherently insecure self.security_menu.menuAction().setVisible( isinstance(self.autorefresh.current_device, VialKeyboard)) # if unlock process was interrupted, we must finish it first if isinstance( self.autorefresh.current_device, VialKeyboard ) and self.autorefresh.current_device.keyboard.get_unlock_in_progress( ): Unlocker.unlock(self.autorefresh.current_device.keyboard) self.autorefresh.current_device.keyboard.reload() for e in [ self.layout_editor, self.keymap_editor, self.firmware_flasher, self.macro_recorder, self.tap_dance, self.combos, self.qmk_settings, self.matrix_tester, self.rgb_configurator ]: e.rebuild(self.autorefresh.current_device) def refresh_tabs(self): self.tabs.clear() for container, lbl in self.editors: if not container.valid(): continue c = EditorContainer(container) self.tabs.addTab(c, tr("MainWindow", lbl)) def load_via_stack_json(self): with urlopen( "https://github.com/vial-kb/via-keymap-precompiled/raw/main/via_keyboard_stack.json" ) as resp: data = resp.read() self.autorefresh.load_via_stack(data) # write to cache with open(os.path.join(self.cache_path, "via_keyboards.json"), "wb") as cf: cf.write(data) def on_sideload_json(self): dialog = QFileDialog() dialog.setDefaultSuffix("json") dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setNameFilters(["VIA layout JSON (*.json)"]) if dialog.exec_() == QDialog.Accepted: with open(dialog.selectedFiles()[0], "rb") as inf: data = inf.read() self.autorefresh.sideload_via_json(data) def on_load_dummy(self): dialog = QFileDialog() dialog.setDefaultSuffix("json") dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setNameFilters(["VIA layout JSON (*.json)"]) if dialog.exec_() == QDialog.Accepted: with open(dialog.selectedFiles()[0], "rb") as inf: data = inf.read() self.autorefresh.load_dummy(data) def lock_ui(self): self.autorefresh._lock() self.tabs.setEnabled(False) self.combobox_devices.setEnabled(False) self.btn_refresh_devices.setEnabled(False) def unlock_ui(self): self.autorefresh._unlock() self.tabs.setEnabled(True) self.combobox_devices.setEnabled(True) self.btn_refresh_devices.setEnabled(True) def unlock_keyboard(self): if isinstance(self.autorefresh.current_device, VialKeyboard): Unlocker.unlock(self.autorefresh.current_device.keyboard) def lock_keyboard(self): if isinstance(self.autorefresh.current_device, VialKeyboard): self.autorefresh.current_device.keyboard.lock() def reboot_to_bootloader(self): if isinstance(self.autorefresh.current_device, VialKeyboard): Unlocker.unlock(self.autorefresh.current_device.keyboard) self.autorefresh.current_device.keyboard.reset() def change_keyboard_layout(self, index): self.settings.setValue("keymap", KEYMAPS[index][0]) KeycodeDisplay.set_keymap_override(KEYMAPS[index][1]) def get_theme(self): return self.settings.value("theme", "Dark") def set_theme(self, theme): themes.set_theme(theme) self.settings.setValue("theme", theme) msg = QMessageBox() msg.setText( tr( "MainWindow", "In order to fully apply the theme you should restart the application." )) msg.exec_() def on_tab_changed(self, index): TabbedKeycodes.close_tray() old_tab = self.current_tab new_tab = None if index >= 0: new_tab = self.tabs.widget(index) if old_tab is not None: old_tab.editor.deactivate() if new_tab is not None: new_tab.editor.activate() self.current_tab = new_tab def about_vial(self): QMessageBox.about( self, "About Vial", 'Vial {}<br><br>' 'Licensed under the terms of the<br>GNU General Public License (version 2 or later)<br><br>' '<a href="https://get.vial.today/">https://get.vial.today/</a>'. format(self.appctx.build_settings["version"])) def closeEvent(self, e): self.settings.setValue("size", self.size()) self.settings.setValue("pos", self.pos()) e.accept()
class DyStockTradeStrategyMarketMonitorWidget(QWidget): """ 股票策略实时监控窗口,动态创建 """ signal = QtCore.pyqtSignal(type(DyEvent())) def __init__(self, eventEngine, strategyCls, strategyState): super().__init__() self._eventEngine = eventEngine self._strategyCls = strategyCls self._registerEvent() self._initUi(strategyState) def _initUi(self, strategyState): self._dataWidget = DyStockTradeStrategyMarketMonitorDataWidget(self._strategyCls) self._indWidget = DyStockTradeStrategyMarketMonitorIndWidget(self._eventEngine, self._strategyCls, strategyState) self._dataLabel = QLabel('数据') self._indLabel = QLabel('指示') grid = QGridLayout() grid.setSpacing(0) grid.addWidget(self._dataLabel, 0, 0) grid.addWidget(self._dataWidget, 1, 0) grid.addWidget(self._indLabel, 2, 0) grid.addWidget(self._indWidget, 3, 0) grid.setRowStretch(0, 1) grid.setRowStretch(1, 30) grid.setRowStretch(2, 1) grid.setRowStretch(3, 30) self.setLayout(grid) # set menu for labels self._dataLabel.setContextMenuPolicy(Qt.CustomContextMenu) self._dataLabel.customContextMenuRequested.connect(self._showLabelContextMenu) self._indLabel.setContextMenuPolicy(Qt.CustomContextMenu) self._indLabel.customContextMenuRequested.connect(self._showLabelContextMenu) self._labelMenu = QMenu(self) action = QAction('叠加', self) action.triggered.connect(self._overlapAct) self._labelMenu.addAction(action) def _stockMarketMonitorUiHandler(self, event): if 'data' in event.data: data = event.data['data']['data'] new = event.data['data']['new'] strategyCls = event.data['class'] if strategyCls.maxUiDataRowNbr is not None: data = data[:strategyCls.maxUiDataRowNbr] self._dataWidget.update(data, new) if 'ind' in event.data: self._indWidget.update(event.data['ind']) def _signalEmitWrapper(self, event): """ !!!Note: The value of signal.emit will always be changed each time you getting. """ self.signal.emit(event) def _registerEvent(self): self.signal.connect(self._stockMarketMonitorUiHandler) self._eventEngine.register(DyEventType.stockMarketMonitorUi + self._strategyCls.name, self._signalEmitWrapper) def _unregisterEvent(self): self.signal.disconnect(self._stockMarketMonitorUiHandler) self._eventEngine.unregister(DyEventType.stockMarketMonitorUi + self._strategyCls.name, self._signalEmitWrapper) def closeEvent(self, event): self._dataWidget.close() self._indWidget.close() self._unregisterEvent() return super().closeEvent(event) def _showLabelContextMenu(self, position): self._labelMenu.popup(QCursor.pos()) def _overlapAct(self): grid = self.layout() # remove self._dataLabel.setText('') self._indLabel.setText('') grid.removeWidget(self._dataLabel) grid.removeWidget(self._dataWidget) grid.removeWidget(self._indLabel) grid.removeWidget(self._indWidget) # add self._tabWidget = QTabWidget() self._tabWidget.addTab(self._dataWidget, '数据') self._tabWidget.addTab(self._indWidget, '指示') grid.addWidget(self._tabWidget, 0, 0) grid.setRowStretch(0, 1) grid.setRowStretch(1, 0) grid.setRowStretch(2, 0) grid.setRowStretch(3, 0) # 设置Tab右键菜单事件 tabBar = self._tabWidget.tabBar() tabBar.setContextMenuPolicy(Qt.CustomContextMenu) tabBar.customContextMenuRequested.connect(self._showTabContextMenu) # 创建TabBar菜单 self._tabBarMenu = QMenu(self) action = QAction('平铺', self) action.triggered.connect(self._flatAct) self._tabBarMenu.addAction(action) def _showTabContextMenu(self, position): self._tabBarMenu.popup(QCursor.pos()) def _flatAct(self): grid = self.layout() # remove self._tabWidget.removeTab(0) self._tabWidget.removeTab(0) grid.removeWidget(self._tabWidget) self._tabWidget.hide() # add self._dataLabel.setText('数据') self._indLabel.setText('指示') grid.addWidget(self._dataLabel, 0, 0) grid.addWidget(self._dataWidget, 1, 0) grid.addWidget(self._indLabel, 2, 0) grid.addWidget(self._indWidget, 3, 0) self._dataWidget.show() self._indWidget.show() grid.setRowStretch(0, 1) grid.setRowStretch(1, 30) grid.setRowStretch(2, 1) grid.setRowStretch(3, 30)
class Window(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setFixedSize(QSize(WIND_HEIGHT, WIND_WIDTH)) self.setWindowTitle('HeadHunter') self.setWindowIcon(QIcon('sources/hh.png')) self.color = '#cfebfd' self.second_color = '#87cefa' self.third_color = '#0000cc' self.start_sal = MIN_SALARY self.data = work_with_data.get_prepocess_data(False) self.categorical_columns = ['Area', 'Employment', 'Experience'] self.binary_columns = list(LANGUAGES) + list(SIZE_COMPANY.keys()) self.model = model.get_forest_model(self.data, self.categorical_columns, self.binary_columns) # 1 Widget self.tabs_lang = QTabWidget(self) self.tabs_lang1 = QWidget() self.tabs_lang2 = QWidget() self.tabs_lang.resize(WIND_HEIGHT, WIND_WIDTH - BUTTON_MENU_WIDTH - 5) self.tabs_lang.move(0, BUTTON_MENU_WIDTH + 5) self.tabs_lang.addTab(self.tabs_lang1, 'Статистика по средней зарплате') self.tabs_lang.addTab(self.tabs_lang2, 'Статистика по количеству вакансий') # 2 Widget self.tabs_city = QTabWidget(self) self.tabs_city1 = QWidget() self.tabs_city2 = QWidget() self.tabs_city.resize(WIND_HEIGHT, WIND_WIDTH - BUTTON_MENU_WIDTH - 5) self.tabs_city.move(0, BUTTON_MENU_WIDTH + 5) self.tabs_city.addTab(self.tabs_city1, 'Статистика по средней зарплате') self.tabs_city.addTab(self.tabs_city2, 'Статистика по количеству вакансий') # 3 Widget self.tabs_map = QTabWidget(self) self.tab_map1 = QWidget() self.tabs_map.resize(WIND_HEIGHT, WIND_WIDTH - BUTTON_MENU_WIDTH - 25) self.tabs_map.move(0, BUTTON_MENU_WIDTH + 25) self.tabs_map.addTab(self.tab_map1, '') # 4 Widget self.tabs_model = QTabWidget(self) self.tab_model1 = QWidget() self.tabs_model.resize(WIND_HEIGHT, WIND_WIDTH - BUTTON_MENU_WIDTH - 25) self.tabs_model.move(0, BUTTON_MENU_WIDTH + 25) self.tabs_model.addTab(self.tab_model1, '') # 1,2 plot self.plot_lang1 = MatPlot(WIND_HEIGHT * 0.25, 0, self.tabs_lang1, self.second_color) self.plot_lang2 = MatPlot(WIND_HEIGHT * 0.25, 0, self.tabs_lang2, self.second_color) # 3,4 plot self.plot_city1 = MatPlot(WIND_HEIGHT * 0.25, 0, self.tabs_city1, self.second_color) self.plot_city2 = MatPlot(WIND_HEIGHT * 0.25, 0, self.tabs_city2, self.second_color) # map self.plot_map1 = MatPlot(0, 0, self.tab_map1, self.color, self.third_color) # button self.button_lang = QPushButton('Статистика\nпо языкам', self) self.button_lang.clicked.connect(lambda: self.show_tab(self.tabs_lang)) self.button_lang.resize(BUTTON_MENU_HEIGHT, BUTTON_MENU_WIDTH) self.button_lang.move(BUTTON_MENU_HEIGHT * 0, 0) self.button_city = QPushButton('Статистика\nпо городам', self) self.button_city.clicked.connect(lambda: self.show_tab(self.tabs_city)) self.button_city.resize(BUTTON_MENU_HEIGHT, BUTTON_MENU_WIDTH) self.button_city.move(BUTTON_MENU_HEIGHT * 1, 0) self.button_map = QPushButton('Востребованность\nв городах', self) self.button_map.clicked.connect(lambda: self.show_tab(self.tabs_map)) self.button_map.resize(BUTTON_MENU_HEIGHT, BUTTON_MENU_WIDTH) self.button_map.move(BUTTON_MENU_HEIGHT * 2, 0) self.button_model = QPushButton('Заработная\nплата', self) self.button_model.clicked.connect( lambda: self.show_tab(self.tabs_model)) self.button_model.resize(BUTTON_MENU_HEIGHT, BUTTON_MENU_WIDTH) self.button_model.move(BUTTON_MENU_HEIGHT * 3, 0) self.button_update = QPushButton('Обновить', self) self.button_update.clicked.connect(self.update_data) self.button_update.resize(BUTTON_MENU_HEIGHT / 3, BUTTON_MENU_WIDTH / 3) self.button_update.move( BUTTON_MENU_HEIGHT * 3 + 2 * BUTTON_MENU_HEIGHT / 3, BUTTON_MENU_WIDTH + 2) # 1-2 filter self.all_filters = {} self.filters_city1 = QFrame(self.tabs_city1) self.filters_city1.resize(FRAME_WIDTH, FRAME_HEIGHT - 50) self.filters_city1.move(10, 10) self.all_filters['City1'] = (self.create_filters(self.filters_city1, 'City1', lang=True, sal=False)) self.filters_city2 = QFrame(self.tabs_city2) self.filters_city2.resize(FRAME_WIDTH, FRAME_HEIGHT) self.filters_city2.move(10, 10) self.all_filters['City2'] = (self.create_filters(self.filters_city2, 'City2', lang=True)) # 3-4 filter self.filters_lang1 = QFrame(self.tabs_lang1) self.filters_lang1.resize(FRAME_WIDTH, FRAME_HEIGHT - 50) self.filters_lang1.move(10, 10) self.all_filters['Lang1'] = (self.create_filters(self.filters_lang1, 'Lang1', area=True, sal=False)) self.filters_lang2 = QFrame(self.tabs_lang2) self.filters_lang2.resize(FRAME_WIDTH, FRAME_HEIGHT) self.filters_lang2.move(10, 10) self.all_filters['Lang2'] = (self.create_filters(self.filters_lang2, 'Lang2', area=True)) # model self.filter_model = {} self.create_filters_model(self.tab_model1) self.button_forecast = QPushButton('Расчет', self.tab_model1) self.button_forecast.clicked.connect(self.create_forecast) self.button_forecast.resize(BUTTON_MENU_HEIGHT, BUTTON_MENU_WIDTH) self.button_forecast.move(WIND_HEIGHT / 2 - BUTTON_MENU_HEIGHT / 2, 300) self.button_forecast.setEnabled(False) self.label_forecast = QLabel(self.tab_model1) self.label_forecast.setAlignment(Qt.AlignCenter) self.label_forecast.resize(WIND_HEIGHT, BUTTON_MENU_WIDTH) self.label_forecast.move(0, 400) self.plot_all() self.show_tab(self.tabs_lang) self.set_style() def show_tab(self, item_view): self.tabs_lang.hide() self.tabs_map.hide() self.tabs_city.hide() self.tabs_model.hide() item_view.show() def create_filters(self, parent, code, lang=False, area=False, sal=True): if sal: label_sal = QLabel(parent) label_sal.setText('Зарплата от') label_sal.resize(100, 15) label_sal.move(5, 125) label_sal_val = QLabel(parent) label_sal_val.move(FRAME_WIDTH - 50, 125) label_sal_val.resize(45, 15) label_sal_val.setAlignment(Qt.AlignRight) label_sal_val.setText(str(self.start_sal)) sld_sal = QSlider(Qt.Horizontal, parent) sld_sal.setMinimum(int(self.start_sal / 5000)) sld_sal.setMaximum(40) sld_sal.setPageStep(1) sld_sal.move(5, 145) sld_sal.resize(FRAME_WIDTH - 10, 20) sld_sal.valueChanged[int].connect( lambda val, tab=code: self.sld_action(val, tab)) else: label_sal_val = None sld_sal = None if lang: combo_lang = QComboBox(parent) combo_lang.setMaxVisibleItems(20) combo_lang.addItem("Все языки") combo_lang.resize(FRAME_WIDTH - 10, 20) combo_lang.move(5, 10) combo_lang.addItems(LANGUAGES) combo_lang.activated.connect( lambda val, tab=code: self.refresh_plot(tab)) else: combo_lang = None if area: combo_area = QComboBox(parent) combo_area.setMaxVisibleItems(20) combo_area.addItem("Все города") combo_area.resize(FRAME_WIDTH - 10, 20) combo_area.move(5, 10) combo_area.addItems( [work_with_data.decode_param(val) for val in AREA]) combo_area.activated.connect( lambda val, tab=code: self.refresh_plot(tab)) else: combo_area = None combo_sizecomp = QComboBox(parent) combo_sizecomp.setMaxVisibleItems(5) combo_sizecomp.addItem("Все компании") combo_sizecomp.resize(FRAME_WIDTH - 10, 20) combo_sizecomp.move(5, 40) combo_sizecomp.addItems([ work_with_data.decode_param(size_comp) for size_comp in SIZE_COMPANY ]) combo_sizecomp.activated.connect( lambda val, tab=code: self.refresh_plot(tab)) combo_exp = QComboBox(parent) combo_exp.setMaxVisibleItems(10) combo_exp.addItem("Любой опыт") combo_exp.resize(FRAME_WIDTH - 10, 20) combo_exp.move(5, 70) combo_exp.addItems([ work_with_data.decode_param(experience) for experience in EXPERIENCE ]) combo_exp.activated.connect( lambda val, tab=code: self.refresh_plot(tab)) combo_empl = QComboBox(parent) combo_empl.setMaxVisibleItems(10) combo_empl.addItem("Любой график") combo_empl.resize(FRAME_WIDTH - 10, 20) combo_empl.move(5, 100) combo_empl.addItems([ work_with_data.decode_param(employment) for employment in EMPLOYMENT ]) combo_empl.activated.connect( lambda val, tab=code: self.refresh_plot(tab)) items = { 'Lang': combo_lang, 'Area': combo_area, 'MinSal': sld_sal, 'SizeComp': combo_sizecomp, 'Employment': combo_empl, 'Experience': combo_exp, 'lbl_min': label_sal_val } return items def create_filters_model(self, parent): checks = {} for i, lang in enumerate(LANGUAGES): check = QCheckBox(parent) check.setText(lang) check.stateChanged.connect(self.check_action) check.move(250 * (i % 4) + 80, 25 * (i // 4) + 25) checks[lang] = check combo_area = QComboBox(parent) combo_area.setMaxVisibleItems(20) combo_area.resize(WIND_HEIGHT / 2 - 80 - 20, 20) combo_area.move(80, 200) combo_area.addItems([work_with_data.decode_param(val) for val in AREA]) combo_empl = QComboBox(parent) combo_empl.setMaxVisibleItems(10) combo_empl.resize(WIND_HEIGHT / 2 - 80 - 20, 20) combo_empl.move(WIND_HEIGHT / 2, 200) combo_empl.addItems([ work_with_data.decode_param(employment) for employment in EMPLOYMENT ]) combo_exp = QComboBox(parent) combo_exp.setMaxVisibleItems(10) combo_exp.resize(WIND_HEIGHT / 2 - 80 - 20, 20) combo_exp.move(80, 240) combo_exp.addItems([ work_with_data.decode_param(experience) for experience in EXPERIENCE ]) combo_sizecomp = QComboBox(parent) combo_sizecomp.setMaxVisibleItems(5) combo_sizecomp.resize(WIND_HEIGHT / 2 - 80 - 20, 20) combo_sizecomp.move(WIND_HEIGHT / 2, 240) combo_sizecomp.addItems([ work_with_data.decode_param(size_comp) for size_comp in SIZE_COMPANY ]) self.filter_model = { 'Lang': checks, 'Area': combo_area, 'Employment': combo_empl, 'Experience': combo_exp, 'SizeComp': combo_sizecomp } def set_style(self): main_style = 'background: #ffffff;' style_combobox = """ QComboBox{{ font-weight: 600; background: {}; border: none; }} QComboBox QAbstractItemView {{ selection-color: #000000; selection-background-color: {}; }} QComboBox::drop-down{{ border: 1px; }} QComboBox::hover{{ background: {}; }} """.format(self.color, self.color, self.second_color) style_slider = """ QSlider::groove:horizontal {{ height: 3px; background: #B0AEB1; }} QSlider::handle:horizontal {{ background: {}; border: 1px solid {}; width: 10px; margin: -10px 0; }} QSlider::sub-page:qlineargradient {{ background: {}; }} """.format(self.color, self.color, self.third_color) style_filters = ''' background-color: #ffffff ''' style_button = ''' QPushButton {{ background-color: {}; font: bold 12px; border: 1px solid #ffffff; }} QPushButton:hover {{ background-color: {}; color: #ffffff; }} '''.format(self.color, self.third_color) style_tabs = ''' QTabBar::tab {height: 0px; width: 0px;}; ''' style_checkbox = """ QCheckBox::indicator:checked { image: url(sources//hh_enabled.png); } QCheckBox::indicator:unchecked { image: url(sources//hh_notenabled.png); } """ for key in self.all_filters: for name_item in ('Area', 'Lang', 'SizeComp', 'Experience', 'Employment'): if self.all_filters[key][name_item] is not None: self.all_filters[key][name_item].setStyleSheet( style_combobox) # for name_item in ('SizeComp', 'Experience', 'Employment'): # self.all_filters[key][name_item].setStyleSheet(style_combobox) if self.all_filters[key]['MinSal'] is not None: self.all_filters[key]['MinSal'].setStyleSheet(style_slider) for key in self.filter_model: if key in ('Area', 'SizeComp', 'Experience', 'Employment'): self.filter_model[key].setStyleSheet(style_combobox) if key in ('Lang', ): for check in self.filter_model[key].values(): check.setStyleSheet(style_checkbox) self.setStyleSheet(main_style) self.filters_city1.setStyleSheet(style_filters) self.filters_city2.setStyleSheet(style_filters) self.filters_lang1.setStyleSheet(style_filters) self.filters_lang2.setStyleSheet(style_filters) self.button_lang.setStyleSheet(style_button) self.button_city.setStyleSheet(style_button) self.button_map.setStyleSheet(style_button) self.button_model.setStyleSheet(style_button) self.button_update.setStyleSheet(style_button) self.tabs_map.setStyleSheet(style_tabs) self.tabs_model.setStyleSheet(style_tabs) self.button_forecast.setStyleSheet(style_button) self.label_forecast.setStyleSheet(""" QLabel {{ font: bold 24px; border: 1px solid #ffffff; color: {}; }} """.format(self.second_color)) # self.label_forecast.setFont(QFont("Times", 8, QFont.Bold)) def plot_all(self): for nametab in ('Lang1', 'Lang2', 'City1', 'City2'): self.refresh_plot(nametab) self.draw_plot_map1() def sld_action(self, value, nametab): self.all_filters[nametab]['lbl_min'].setText(str(value * 5000)) self.refresh_plot(nametab) def check_action(self): active_checks = [] for lang, checkbox in self.filter_model['Lang'].items(): if checkbox.isChecked(): active_checks.append(lang) if len(active_checks) >= MAX_LANG_MODEL: for checkbox in self.filter_model['Lang'].values(): if not checkbox.isChecked(): checkbox.setEnabled(False) else: for checkbox in self.filter_model['Lang'].values(): checkbox.setEnabled(True) self.button_forecast.setEnabled(bool(len(active_checks))) def refresh_plot(self, tabname): df_t = self.data sal = self.all_filters[tabname]['MinSal'] if sal is not None: min_sal = sal.value() * 5000 df_t = self.data[self.data['Salary'] > min_sal] area = self.all_filters[tabname]['Area'] if area is not None and area.currentIndex(): area = work_with_data.encode_param(area.currentText()) df_t = df_t[df_t['Area'] == area] lang = self.all_filters[tabname]['Lang'] if lang is not None and lang.currentIndex(): lang = lang.currentText() df_t = df_t[df_t[lang] == 1] if self.all_filters[tabname]['SizeComp'].currentIndex(): size_comp = work_with_data.encode_param( self.all_filters[tabname]['SizeComp'].currentText()) df_t = df_t[df_t[size_comp] == 1] if self.all_filters[tabname]['Experience'].currentIndex(): exp = work_with_data.encode_param( self.all_filters[tabname]['Experience'].currentText()) df_t = df_t[df_t['Experience'] == exp] if self.all_filters[tabname]['Employment'].currentIndex(): empl = work_with_data.encode_param( self.all_filters[tabname]['Employment'].currentText()) df_t = df_t[df_t['Employment'] == empl] if tabname == 'Lang1': self.draw_plot_lang1(df_t) elif tabname == 'Lang2': self.draw_plot_lang2(df_t) elif tabname == 'City1': self.draw_plot_city1(df_t) elif tabname == 'City2': self.draw_plot_city2(df_t) def draw_plot_lang1(self, data=None): if data is None: data = self.data mass_sal = [(lang, data[data[lang] == 1]['Salary'].mean()) for lang in LANGUAGES] mass_sal = [val for val in mass_sal if str(val[1]) != 'nan'] mass_sal.sort(key=lambda x: -x[1]) temp = list(zip(*mass_sal)) if not temp: temp = [[], []] self.plot_lang1.plot_bar(*temp, 'Средняя зарплата по языкам') def draw_plot_lang2(self, data=None): if data is None: data = self.data count_vac = [(lang, data[data[lang] == 1].shape[0]) for lang in LANGUAGES] count_vac.sort(key=lambda x: -x[1]) count_vac = filter(lambda x: x[1] > 0, count_vac) temp = list(zip(*count_vac)) if not temp: temp = [[], []] self.plot_lang2.plot_bar(*temp, 'Количество вакансий по языкам') def draw_plot_city1(self, data=None): if data is None: data = self.data mass_sal = [(area, data[data['Area'] == area]['Salary'].mean()) for area in AREA.keys()] mass_sal = [val for val in mass_sal if str(val[1]) != 'nan'] mass_sal.sort(key=lambda x: -x[1]) temp = list(zip(*mass_sal)) if not temp: temp = [[], []] else: temp[0] = [work_with_data.decode_param(city) for city in temp[0]] self.plot_city1.plot_bar(*temp, 'Средняя зарплата по городам') def draw_plot_city2(self, data=None): if data is None: data = self.data count_vac = [(area, data[data['Area'] == area].shape[0]) for area in AREA.keys()] count_vac.sort(key=lambda x: -x[1]) count_vac = filter(lambda x: x[1] > 0, count_vac) temp = list(zip(*count_vac)) if not temp: temp = [[], []] else: temp[0] = [work_with_data.decode_param(city) for city in temp[0]] self.plot_city2.plot_bar(*temp, 'Количество вакансий по городам') def draw_plot_map1(self, data=None): if data is None: data = self.data mass_sal = [(area, data[data['Area'] == area].shape[0]) for area in AREA.keys()] mass_sal = filter(lambda x: x[1] > 0, mass_sal) temp = list(zip(*mass_sal)) min_vac = min(temp[1]) temp[1] = [vac / min_vac for vac in temp[1]] self.plot_map1.plot_map(*temp, 'Количество вакансий по городам') def create_forecast(self): vacancy = [] for key in self.categorical_columns: vacancy.append( work_with_data.encode_param( self.filter_model[key].currentText())) for checkbox in self.filter_model['Lang'].values(): vacancy.append(int(checkbox.isChecked())) for size_comp in SIZE_COMPANY: vacancy.append( int( work_with_data.encode_param(self.filter_model['SizeComp']. currentText()) == size_comp)) df = pd.DataFrame([vacancy], columns=self.categorical_columns + self.binary_columns) self.label_forecast.setText('Возможная зарплата: {:.0f} руб'.format( self.model.get_predict(df)[0])) def update_data(self): answer = QMessageBox.question(self, 'Обновление данных', 'Вы хотите обновить данные?', QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Cancel) if answer == QMessageBox.Ok: self.data = work_with_data.get_prepocess_data(True) self.model = model.get_forest_model(self.data, self.categorical_columns, self.binary_columns) self.plot_all()