class SongsTable_Container(FFrame): def __init__(self, app, parent=None): super().__init__(parent) self._app = app self.songs_table = None self.table_control = TableControl(self._app) self._layout = QVBoxLayout(self) self.setup_ui() def setup_ui(self): self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setSpacing(0) self._layout.addWidget(self.table_control) def set_table(self, songs_table): if self.songs_table: self._layout.replaceWidget(self.songs_table, songs_table) self.songs_table.close() del self.songs_table else: self._layout.addWidget(songs_table) self._layout.addSpacing(10) self.songs_table = songs_table
class PlotWindow(QWidget): def __init__(self, data): super().__init__() self.plot_tabs(data) self.setWindowTitle('Pipeline results') self.show() def widget(self, y, x=None, labels={'left': '', 'bottom': ''}): pg.setConfigOption('background', 'w') pg.setConfigOption('foreground', 'k') pw = pg.PlotWidget(pen=None, labels=labels) pw.plot(x=x, y=y, symbol='o', symbolSize=5, pen=None) return pw def plot_tabs(self, data): import numpy as np layout = QVBoxLayout() self.setLayout(layout) tabs = QTabWidget() layout.addWidget(tabs) ''' Optimization tab ''' plot_data = data['Optimization'] tab_widget = self.widget(x=plot_data['x'], y=plot_data['y'], labels=plot_data['labels']) tabs.addTab(tab_widget, 'Optimization') ''' Cost vs parameter tab ''' tab_widget = QWidget() self.tab_layout = QVBoxLayout() tab_widget.setLayout(self.tab_layout) tabs.addTab(tab_widget, '1D') box = QComboBox() box.currentTextChanged.connect(self.plot_axis) pipe_data = data['Data'] self.points = np.atleast_2d(data['Data']['points']) self.costs = np.array(data['Data']['costs']) self.axis_widget = self.widget(x=self.points[:, 0], y=self.costs) self.tab_layout.addWidget(box) for item in range(self.points.shape[1]): box.addItem(str(item)) self.tab_layout.addWidget(self.axis_widget) def plot_axis(self, axis): axis = int(axis) new_widget = self.widget(x=self.points[:, axis], y=self.costs, labels={ 'bottom': str(axis), 'left': 'Result' }) self.tab_layout.replaceWidget(self.axis_widget, new_widget) self.axis_widget = new_widget
class MyApp(env, QMainWindow, Ui_MainWindow,): def __init__(self): self.env = env QMainWindow.__init__(self) Ui_MainWindow.__init__(self) super().__init__() self.initUI() self.initBtn() self.initFrame() def initFrame(self): self.main_widget = self.frame self.layout = QVBoxLayout(self.main_widget) self.f = MyMplCanvas(self.main_widget) self.layout.addWidget(self.f) def initUI(self): self.setupUi(self) self.setWindowTitle("PyQt5结合Matplotlib绘图") self.setWindowIcon(QIcon("rocket.ico")) # 设置图标,linux下只有任务栏会显示图标 self.show() def initBtn(self): self.btnPlot.clicked.connect(self.plotButton_callback) self.btnPlot.setToolTip("Button") def plotButton_callback(self): self.drawFrame() def drawFrame(self): dc = MyDynamicMplCanvas(self.env, self.f, width=5, height=4, dpi=100) self.layout.replaceWidget(self.f,dc) # 替换控件
class SongsTableContainer(MFrame): def __init__(self, app, parent=None): super().__init__(parent) self._app = app self.songs_table = None self.table_control = TableControl(self._app) self._layout = QVBoxLayout(self) self.setup_ui() def set_table(self, songs_table): if self.songs_table: self._layout.replaceWidget(self.songs_table, songs_table) self.songs_table.deleteLater() else: self._layout.addWidget(songs_table) self._layout.addSpacing(10) self.songs_table = songs_table def setup_ui(self): self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setSpacing(0) self._layout.addWidget(self.table_control)
class PageEditor(QWidget): def __init__(self): QWidget.__init__(self) self.placeholder = QWidget() hbox = QHBoxLayout() hbox.setAlignment(Qt.AlignLeft) hbox.setSpacing(10) addSection = HyperLink("(+) Add Section") addFullSection = HyperLink("(+) Add Full Width Section") l = QVBoxLayout() self.layout = QVBoxLayout() l.addLayout(self.layout) l.addWidget(self.placeholder) hbox.addWidget(addSection) hbox.addWidget(addFullSection) self.layout.addLayout(hbox) self.layout.addStretch() self.setLayout(l) self.setAcceptDrops(True) addSection.clicked.connect(self.addNormalSection) addFullSection.clicked.connect(self.addFullSection) def enableColumnAcceptDrop(self, mode): for i in range(self.layout.count()): ce = self.layout.itemAt(i).widget() if isinstance(ce, ColumnEditor): ce.enableColumnAcceptDrop(mode) def enableSectionAcceptDrop(self, mode): for i in range(self.layout.count()): se = self.layout.itemAt(i).widget() if isinstance(se, SectionEditor): se.enableColumnAcceptDrop(mode) def addFullSection(self): se = SectionEditor(True) self.addSection(se) ce = self.getContentEditor() if ce: sec = Section() sec.fullwidth = True se.load(sec) ce.content.appendSection(sec) ce.editChanged("Add Section") def addNormalSection(self): se = SectionEditor(False) self.addSection(se) ce = self.getContentEditor() if ce: sec = Section() sec.fullwidth = False se.load(sec) ce.content.appendSection(sec) ce.editChanged("Add Section") def addSection(self, se): se.sectionEditorCopied.connect(self.copySection) self.layout.insertWidget(self.layout.count() - 2, se) def sections(self): list = [] for i in range(self.layout.count()): se = self.layout.itemAt(i).widget() if isinstance(se, SectionEditor): list.append(se) return list def removeSectionEditor(self, se): self.layout.removeWidget(se) def removeSection(self, se): sec = se.section se.hide() self.layout.removeWidget(se) del se ce = self.getContentEditor() if ce: ce.content.removeSection(sec) ce.editChanged("Delete Section") def copySection(self, se): see = SectionEditor(se.fullwidth) self.addSection(see) ce = self.getContentEditor() if ce: sec = se.section.clone() see.load(sec) ce.content.appendSection(sec) ce.editChanged("Copy Section") def getContentEditor(self): sa = self.parentWidget() if sa: vp = sa.parentWidget() if vp: cee = vp.parentWidget() if cee: return cee return None def dragEnterEvent(self, event): myData = event.mimeData() if myData: se = myData.getData() if isinstance(se, SectionEditor): # insert a dropzone at the end self.layout.addWidget(DropZone(myData.width, myData.height)) event.accept() else: event.ignore() else: event.ignore() def dragLeaveEvent(self, event): # remove dropzones for i in range(self.layout.count()): dz = self.layout.itemAt(i).widget() if isinstance(dz, DropZone): dz.hide() self.layout.removeWidget(dz) del dz break event.accept() def dragMoveEvent(self, event): myData = event.mimeData() if myData: se = myData.getData() if isinstance(se, SectionEditor): height = 0 row = 0 # evaluate position for the dropzone to be placed for i in range(self.layout.count()): editor = self.layout.itemAt(i).widget() if isinstance(editor, SectionEditor): if event.pos().y() > height and event.pos().y( ) < height + editor.height(): break height += editor.height() row = row + 1 # find dropzone and replace it to new location for i in range(self.layout.count()): dz = self.layout.itemAt(i).widget() if isinstance(dz, DropZone): if i != row: self.layout.insertWidget(row, dz) break event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() else: event.ignore() def dropEvent(self, event): myData = event.mimeData() if myData: se = myData.getData() if isinstance(se, SectionEditor): # place the dragged SectionEditor to the place where DropZone is now for i in range(self.layout.count()): dz = self.layout.itemAt(i).widget() if isinstance(dz, DropZone): dz.hide() self.layout.replaceWidget(dz, se) new_pos = i se.show() del dz break ce = self.getContentEditor() if ce: ce.content.changeSectionPos(se.section, new_pos) ce.editChanged("Move Section") event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() else: event.ignore()
class PyTouchCubeGUI(QMainWindow): item_selected = None props_current = None printer_select = None save_printable_button = None def __init__(self, app: QApplication): super().__init__() Settings.load() self.setWindowTitle(APP_NAME) self.app = app app.setApplicationName(APP_NAME) app.setApplicationDisplayName(APP_NAME) self.preview_image = QLabel('No items to preview') self.preview_image.setFixedHeight(USABLE_HEIGHT) self.props_empty = False self.save_image_button = QPushButton('Save image') self.save_image_button.setDisabled(True) self.tree_view = ItemView() self.items = self.create_model() self.item_data = [] self.tree_view.setRootIsDecorated(False) # self.tree_view.setAlternatingRowColors(True) self.tree_view.setModel(self.items) self.tree_view.clicked.connect(self.tree_view_clicked) self.tree_view.rowMoved.connect(self.tree_view_reorder) self.tree_view.setDragEnabled(True) self.tree_view.setDragDropMode(QTreeView.InternalMove) self.tree_view.setItemsExpandable(False) self.tree_view.setDragDropOverwriteMode(False) root = QVBoxLayout() items_layout = QHBoxLayout() group = QGroupBox('Source items:') layout = QVBoxLayout() layout.addWidget(self.tree_view) buttons = QHBoxLayout() add_menu = QMenu() add_menu.addAction(Text.get_add_add_action(self)) add_menu.addAction(Image.get_add_add_action(self)) add_menu.addAction(Barcode.get_add_add_action(self)) add_menu.addAction(QrCode.get_add_add_action(self)) add_menu.addSeparator() add_menu.addAction(Spacing.get_add_add_action(self)) add_button = QPushButton('Add') add_button.setMenu(add_menu) buttons.addWidget(add_button) #buttons.addWidget(add_text_button) #buttons.addWidget(add_barcode_button) buttons.addStretch() buttons.setSpacing(1) b_down = QPushButton('⬇︎') b_down.clicked.connect(lambda _: self.move_item(1)) b_up = QPushButton('⬆︎') b_up.clicked.connect(lambda _: self.move_item(-1)) b_delete = QPushButton('Delete') b_delete.clicked.connect(self.delete_item) b_clone = QPushButton('Copy') b_clone.clicked.connect(self.on_clone) buttons.addWidget(b_clone) buttons.addSpacing(10) buttons.addWidget(b_up) buttons.addWidget(b_down) buttons.addSpacing(10) buttons.addWidget(b_delete) layout.addLayout(buttons) group.setLayout(layout) items_layout.addWidget(group) self.property_group = QGroupBox('Item properties:') self.props_layout = QVBoxLayout() self.property_group.setLayout(self.props_layout) self.props_current = QLabel() self.props_layout.addWidget(self.props_current) self.save_printable_button = QPushButton('Save Changes') self.save_printable_button.clicked.connect(self.save_props) self.props_layout.addWidget(self.save_printable_button) self.update_props() items_layout.addWidget(self.property_group) root.addLayout(items_layout) group = QGroupBox('Preview:') layout = QVBoxLayout() preview_wrapper = QScrollArea(self) #prev_layout = QHBoxLayout() preview_wrapper.setWidget(self.preview_image) preview_wrapper.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) preview_wrapper.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) preview_wrapper.setWidgetResizable(True) preview_wrapper.setFixedHeight(USABLE_HEIGHT) layout.addWidget(preview_wrapper) # layout.addWidget(self.save_image_button) group.setLayout(layout) group.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)) root.addWidget(group) self.printer_select = QComboBox(self) fs_model = QFileSystemModel(self) #model_proxy = QSortFilterProxyModel(self) #model_proxy.setSourceModel(fs_model) # fs_model.setNameFilters(['tty.PT-P3*']) potential_printer = None printers = QStandardItemModel() #for p in QDir('/dev').entryList(['tty*'], QDir.System, QDir.Name): # if p.startswith('tty.'): for p in LabelMaker.list_serial_ports(): # pprint(p.__dict__) item = [QStandardItem(p.name), QStandardItem(p.device)] print(p.name) printers.appendRow(item) ''' item = QStandardItem('/dev/' + p) printers.appendRow(item) if p.startswith('tty.PT-P3'): potential_printer = item ''' #print(printers.entryList()) #model_proxy.setRecursiveFilteringEnabled(True) #model_proxy.setFilterKeyColumn(0) fs_model.setRootPath('/dev/') #/Users/nilsmasen') fs_model.setFilter(QDir.System) dev_index = fs_model.index('/dev') #proxy_dev = model_proxy.mapFromSource(dev_index) self.printer_select.setModel(printers) if potential_printer is not None: index = printers.indexFromItem(potential_printer) self.printer_select.setCurrentIndex(index.row()) #printer_select.setRootModelIndex(dev_index) #printer_select.setRootIndex(dev_index) #printer_select.setExpanded(dev_index, True) #model_proxy.setFilterWildcard('tty*') bottom_box = QGroupBox('Print label: ') bottom_bar = QHBoxLayout() bottom_bar.addWidget(QLabel('Print device:')) bottom_bar.addWidget(self.printer_select) bottom_bar.addStretch() # /dev/tty.PT-P300BT0607-Serial print_button = QPushButton('Print') print_button.setFixedWidth(100) bottom_bar.addWidget(print_button) print_button.clicked.connect(self.print_clicked) bottom_box.setLayout(bottom_bar) root.addWidget(bottom_box) root_widget = QWidget() root_widget.setFixedWidth(800) root_widget.setLayout(root) self.setCentralWidget(root_widget) menu = QMenuBar() self.setMenuBar(menu) menu.setWindowTitle(APP_NAME) tools_menu = menu.addMenu('Python') prefs = QAction('&Preferences', self) prefs.triggered.connect(self.on_prefs) tools_menu.addAction(prefs) about = QAction('About ' + APP_NAME, self) about.triggered.connect(self.on_prefs) about.setMenuRole(QAction.AboutRole) tools_menu.addAction(about) file_menu = menu.addMenu('Label') act_new = QAction('&New', self) act_new.triggered.connect(self.on_new) file_menu.addAction(act_new) file_menu.addSeparator() act_open = QAction('&Open', self) act_open.triggered.connect(self.on_open) act_open.setShortcut(QKeySequence('Ctrl+O')) file_menu.addAction(act_open) file_menu.addSeparator() act_save = QAction('&Save', self) act_save.triggered.connect(self.on_save) act_save.setShortcut(QKeySequence("Ctrl+S")) file_menu.addAction(act_save) act_save_as = QAction('Save &as...', self) act_save_as.triggered.connect(self.on_save_as) act_save_as.setShortcut(QKeySequence("Ctrl+Shift+S")) file_menu.addAction(act_save_as) file_menu.addSeparator() file_menu.addAction(QAction('&Export image', self)) # menu.setNativeMenuBar(False) def on_new(self): self.item_data = [] self.items.clear() self.update_items() self.update_preview() def on_prefs(self): QMessageBox.information( self, "Info", "{0} v{1}\n\nhttps://github.com/piksel/pytouch-cube".format( APP_NAME, APP_VERSION)) def run(self): self.show() #self.add_item(Text(TextData('foo'))) #self.add_item(Text(TextData('Bar1'))) #self.add_item(Text(TextData('Bar2'))) #self.add_item(Spacing(SpacingData(10))) #self.add_item(Text(TextData('baz'))) # self.add_item(Barcode(BarcodeData('123456789012'))) # self.add_item(Barcode(BarcodeData('ACE222', 'code128'))) self.app.exec_() def on_save(self): if self.current_file is None: self.on_save_as() else: self.save() def on_save_as(self): user_home = os.path.expanduser('~') save_initial_path = os.path.join(user_home, 'Documents') if not os.path.isdir(save_initial_path): save_initial_path = user_home file_path, format = QFileDialog.getSaveFileName( self, caption='Save Label', directory=save_initial_path, filter='Label Files (*.p3label)') if len(file_path) <= 0: return self.current_file = file_path self.save() def on_open(self): user_home = os.path.expanduser('~') open_initial_path = os.path.join(user_home, 'Documents') if not os.path.isdir(open_initial_path): open_initial_path = user_home file_path, format = QFileDialog.getOpenFileName( self, caption='Open Label', directory=open_initial_path, filter='Label Files (*.p3label)') if len(file_path) <= 0: return self.current_file = file_path self.open() def save(self): with open(self.current_file, 'wb') as file: pickler = pickle.Pickler(file) pickler.dump(self.item_data) def open(self): with open(self.current_file, 'rb') as file: unpickler = pickle.Unpickler(file) self.item_data = unpickler.load() self.update_items() self.update_preview() def print_clicked(self): log_console = QTextEdit(self) log_console.setReadOnly(True) font = QFont('Fira') font.setStyleHint(QFont.Monospace, QFont.PreferDefault) font.setFamilies([ 'Fira', 'Source Code Pro', 'Monaco', 'Consolas', 'Monospaced', 'Courier' ]) log_console.setFont(font) modal = QDialog(self) modal_layout = QVBoxLayout(self) modal_layout.addWidget(log_console) close = QPushButton('close') close.setDisabled(True) close.clicked.connect(lambda _: modal.close()) modal_layout.addWidget(close) modal.setLayout(modal_layout) modal.setFixedWidth(self.width() * .9) modal.setFixedHeight(self.height() * .9) modal.open() def fmt_log(message): now = datetime.datetime.now() return '{0} {1}'.format(now.isoformat(), message) def log(message): log_console.insertPlainText('\n' + fmt_log(message)) log_console.ensureCursorVisible() def done(exception): if exception is not None: log('Failed to print due to the following error:\n') log_console.insertHtml( '<pre style="color:red">{0}</pre>'.format(exception)) else: log('Printing completed without any errors!\n') close.setDisabled(False) log_console.insertPlainText(fmt_log('Starting print thread...')) print_device = self.printer_select.currentText() self.print_thread = PrintThread(QImage(self.print_image), print_device) self.print_thread.log.connect(log) self.print_thread.done.connect(done) self.print_thread.start() def tree_view_clicked(self, index): self.item_selected = index.row() self.update_props() def move_item(self, direction): current = self.tree_view.currentIndex() print(direction, current) if not current.isValid() or current.row() < 0: print('invalid index', current.row()) self.tree_view.repaint() return old = current.row() new = current.row() + direction if new < 0 or new >= self.items.rowCount(): print('cannot move from', old, 'to', new) return # self.items.moveRow(current.parent(), old, current.parent(), new) self.tree_view_reorder(old, new) self.update_items() self.tree_view.setCurrentIndex(current.sibling(new, 0)) self.tree_view.repaint() def delete_item(self): current = self.tree_view.currentIndex() if not current.isValid() or current.row() < 0: return self.item_data.remove(self.item_data[current.row()]) self.items.removeRow(current.row()) self.update_items() self.update_preview() def on_clone(self): current = self.tree_view.currentIndex() if not current.isValid() or current.row() < 0: return original = self.item_data[current.row()] copy = original.__class__(original.data.clone()) new_index = current.row() + 1 self.item_data.insert(new_index, copy) self.update_items() self.update_preview() self.tree_view.setCurrentIndex(self.items.index(new_index, 0)) self.tree_view.repaint() self.item_selected = new_index self.update_props() def tree_view_reorder(self, old, new): item = self.item_data.pop(old) self.item_data.insert(new, item) self.update_preview() print(old, '=>', new) return item def create_model(self): model = QStandardItemModel(0, 2, self) model.setHeaderData(ModelCol.TYPE.value, Qt.Horizontal, 'Type') model.setHeaderData(ModelCol.DATA.value, Qt.Horizontal, 'Data') return model def add_item(self, item: Printable): current = self.tree_view.currentIndex() row = self.items.rowCount() if current.isValid(): row = current.row() self.items.insertRow(row, item.get_list_item()) self.item_data.insert(row, item) if current.isValid(): self.tree_view.setCurrentIndex(current) else: self.tree_view.setCurrentIndex(self.items.createIndex(row, 0)) self.item_selected = row self.update_preview() self.update_props() def save_props(self): if isinstance(self.props_current, PropsEdit): self.props_current.save() current = self.tree_view.currentIndex() self.update_items() self.tree_view.setCurrentIndex(current) def update_items(self, keep_index=False): current = self.tree_view.currentIndex() for row in range(0, len(self.item_data)): item = self.item_data[row].get_list_item() for col in range(0, len(item)): self.items.setItem(row, col, item[col]) if keep_index: self.tree_view.setCurrentIndex(current) def update_preview(self): item_renders = [] width_needed = 0 for i in range(0, len(self.item_data)): render = self.item_data[i].render() render_error = self.item_data[i].get_render_error() if render_error is not None: QMessageBox.warning( self, 'Failed to render item', 'Failed to render item:\n' + str(render_error)) item_renders.append(render) width_needed += render.width() x = 0 image = QImage(width_needed, USABLE_HEIGHT, QImage.Format_Mono) image.fill(QColor(255, 255, 255)) painter = QPainter(image) for render in iter(item_renders): painter.drawImage(x, 0, render) x += render.width() painter.end() del painter self.print_image = image self.preview_image.setPixmap(QPixmap.fromImage(image)) self.preview_image.repaint() def update_props(self): if self.item_selected is None: if self.props_empty: return new_widget = make_props_empty(self) if self.save_printable_button is not None: self.save_printable_button.setEnabled(False) self.props_empty = True else: item: Printable = self.item_data[self.item_selected] new_widget = item.get_props_editor(self) self.save_printable_button.setEnabled(True) self.props_layout.replaceWidget(self.props_current, new_widget) self.props_current.close() self.props_current = new_widget
class MainPanel(QWidget): def __init__(self, parent): super().__init__(parent) self.db_wrapper = DatabaseWrapper() self.table_name = "Weight Loss" self.setStyleSheet(""" QWidget{ color:#c7c7c7; font-weight: bold; } QPushButton{ background-color: rgba(0, 0, 0, 0); border: 1px solid; font-size: 18px; font-weight: bold; border-color: #808080; min-height: 28px; white-space:nowrap; text-align: left; padding-left: 5%; font-family: Montserrat; } QPushButton:hover:!pressed{ border: 2px solid; border-color: #747474; } QPushButton:pressed{ border: 2px solid; background-color: #323232; border-color: #6C6C6C; } QComboBox{ border-radius: 4px; font-size: 18px; font-weight: bold; white-space:nowrap; text-align: left; padding-left: 5%; font-family: Montserrat; min-height: 28px; background-color: #440D0F; } QComboBox:down-arrow{ width: 0px; height: 0px; background: #d3d3d3; opacity:0 } QComboBox:drop-down{ background-color: #440D0F; border: 0px; opacity:0; border-radius: 0px; width: 0px; height: 0px; } QComboBox:hover:!pressed{ background-color: #5D1A1D; } QComboBox:pressed{ background-color: #551812; } """) self.db_wrapper.create_local_table(self.table_name) self.db_wrapper.create_local_table("Nutrition") if self.db_wrapper.local_table_is_empty("Nutrition"): self.db_wrapper.insert_default_values("Nutrition") if self.db_wrapper.local_table_is_empty(self.table_name): self.db_wrapper.insert_default_values(self.table_name) self.fetch_user_data() self.date = datetime.today().strftime("%d/%m/%Y") self.current_year = datetime.today().year self.calorie_goal = self.db_wrapper.fetch_local_column( "Nutrition", "calorie_goal") self.units = "kg" if self.db_wrapper.fetch_local_column( "Users", "units") == "metric" else "lb" weight_loss_units = "kg" if self.db_wrapper.fetch_local_column( self.table_name, "units") == "metric" else "lb" self.weight_history = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "weight_history")) if self.units != weight_loss_units: units_name = "metric" if self.units == "kg" else "imperial" self.db_wrapper.update_table_column(self.table_name, "units", units_name) if units_name == "metric": for date in self.weight_history: self.weight_history[date] = str( pounds_to_kg(self.weight_history[date])) elif units_name == "imperial": for date in self.weight_history: self.weight_history[date] = str( kg_to_pounds(self.weight_history[date])) self.db_wrapper.update_table_column( self.table_name, "weight_history", json.dumps(self.weight_history)) self.preferred_activity = self.db_wrapper.fetch_local_column( self.table_name, "preferred_activity") self.cardio_history = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "cardio_history")) if not self.date in self.cardio_history: self.add_date_to_cardio_history() if not self.date in self.weight_history: self.add_date_to_weight_history() self.init_cardio_labels() self.create_panel() def create_panel(self): grid = QGridLayout() grid.addLayout(self.create_description(), 0, 0, 1, 1) grid.addWidget(self.create_graph(), 1, 0, 4, 1) grid.addLayout(self.create_bottom_layout(), 5, 0, 3, 1) self.setLayout(grid) def create_description(self): description = QVBoxLayout() description_font = QFont("Montserrat", 12) description_label = QLabel( "Keep notes and track your weight loss journey.", self) description_label.setFont(description_font) description_label.setFixedHeight(20) description.addWidget(description_label) return description def create_graph(self): self.graph_layout = QVBoxLayout() graph = WeightLossGraphCanvas( self.db_wrapper.months[datetime.today().month - 1], self.current_year, self) toolbar = NavigationToolbar(graph, self) toolbar.setStyleSheet("background-color: white;") combobox_layout = QHBoxLayout() self.months_combobox = QComboBox() months = [] for entry in self.weight_history: month = entry.split("/")[1] for month_name, code in self.db_wrapper.months_mappings.items(): if code == month: month = month_name if not month in months: months.append(month) if len(months) == 0: months.append(self.db_wrapper.months[datetime.today().month - 1]) self.months_combobox.addItems(months) self.months_combobox.setCurrentText( self.db_wrapper.months[datetime.today().month - 1]) self.months_combobox.currentTextChanged.connect( lambda month: self.change_month_graph(month)) self.change_year_combobox = QComboBox() years = [] for entry in self.weight_history: if not entry.split("/")[-1] in years: years.append(entry.split("/")[-1]) if len(years) == 0: years.append(str(self.current_year)) self.change_year_combobox.addItems(list(reversed(years))) self.change_year_combobox.currentTextChanged.connect( lambda year: self.change_year_graph(year)) combobox_layout.addWidget(self.months_combobox) combobox_layout.addWidget(self.change_year_combobox) self.graph_layout.addWidget(toolbar) self.graph_layout.addWidget(graph) self.graph_layout.addLayout(combobox_layout) framed_graph = QFrame(self) framed_graph.setFrameStyle(QFrame.Box) framed_graph.setLineWidth(3) framed_graph.setLayout(self.graph_layout) return framed_graph def create_bottom_layout(self): bottom_layout = QHBoxLayout() bottom_layout.addWidget(self.create_weight_loss()) bottom_layout.addWidget(self.create_cardio_notes()) return bottom_layout def create_weight_loss(self): weight_loss = QVBoxLayout() main_label = QLabel("Weight Loss") main_label.setFont(QFont("Ariel", 18, weight=QFont.Bold)) current_weight_layout = QHBoxLayout() self.current_weight_label = QLabel(" ".join( ["Current Weight:", self.current_weight, self.units])) update_current_weight_button = QPushButton("Update") update_current_weight_button.clicked.connect( lambda: self.update_value("Current Weight", self.current_weight)) current_weight_layout.addWidget(self.current_weight_label) current_weight_layout.addWidget(update_current_weight_button) weight_goal_layout = QHBoxLayout() self.weight_goal_label = QLabel(" ".join( ["Weight Goal:", self.goal_weight, self.units])) update_weight_goal_label = QPushButton("Update") update_weight_goal_label.clicked.connect( lambda: self.update_value("Weight Goal", self.goal_weight)) weight_goal_layout.addWidget(self.weight_goal_label) weight_goal_layout.addWidget(update_weight_goal_label) loss_per_week_layout = QHBoxLayout() self.loss_per_week_label = QLabel(" ".join( ["Loss Per Week:", str(self.loss_per_week), self.units])) update_loss_per_week_label = QPushButton("Update") update_loss_per_week_label.clicked.connect( lambda: self.update_value("Loss Per Week", self.loss_per_week)) loss_per_week_layout.addWidget(self.loss_per_week_label) loss_per_week_layout.addWidget(update_loss_per_week_label) calorie_intake_layout = QHBoxLayout() calorie_intake_label = QLabel(" ".join( ["Calorie Intake:", str(self.calorie_goal), "kcal"])) calorie_intake_layout.addWidget(calorie_intake_label) history_layout = QHBoxLayout() weight_loss_history_button = QPushButton("History") weight_loss_history_button.clicked.connect( lambda: self.show_weight_history()) history_layout.addWidget(weight_loss_history_button) weight_loss.addWidget(main_label) weight_loss.addLayout(calorie_intake_layout) weight_loss.addLayout(current_weight_layout) weight_loss.addLayout(weight_goal_layout) weight_loss.addLayout(loss_per_week_layout) weight_loss.addLayout(history_layout) weight_loss.setSpacing(5) framed_layout = QFrame() framed_layout.setObjectName("graphObj") framed_layout.setFrameStyle(QFrame.Box) framed_layout.setLineWidth(3) framed_layout.setStyleSheet("""#graphObj {color: #322d2d;}""") framed_layout.setLayout(weight_loss) return framed_layout def create_cardio_notes(self): cardio_notes = QVBoxLayout() main_label = QLabel("Cardio Notes") main_label.setFont(QFont("Ariel", 18, weight=QFont.Bold)) preferred_activity_layout = QHBoxLayout() self.preferred_activity_label = QLabel(" ".join( ["Preferred Activity:", self.preferred_activity])) self.preferred_activity_dropdown = QComboBox() self.preferred_activity_dropdown.addItems( ["Running", "Walking", "Cycling", "Swimming"]) self.preferred_activity_dropdown.setCurrentText( self.preferred_activity) self.preferred_activity_dropdown.currentTextChanged.connect( lambda activity: self.set_new_preferred_activity(activity)) preferred_activity_layout.addWidget(self.preferred_activity_label) preferred_activity_layout.addWidget(self.preferred_activity_dropdown) time_spent_layout = QHBoxLayout() self.time_spent_label = QLabel(" ".join( ["Time Spent:", self.time_spent, "min"])) update_time_spent_label = QPushButton("Update") update_time_spent_label.clicked.connect( lambda: self.update_value("Time Spent", self.time_spent)) time_spent_layout.addWidget(self.time_spent_label) time_spent_layout.addWidget(update_time_spent_label) calories_burnt_layout = QHBoxLayout() self.calories_burnt_label = QLabel(" ".join( ["Calories Burnt:", self.calories_burnt, "kcal"])) update_calories_burnt_label = QPushButton("Update") update_calories_burnt_label.clicked.connect( lambda: self.update_value("Calories Burnt", self.calories_burnt)) calories_burnt_layout.addWidget(self.calories_burnt_label) calories_burnt_layout.addWidget(update_calories_burnt_label) distance_travelled_layout = QHBoxLayout() self.distance_travelled_label = QLabel(" ".join( ["Distance Travelled:", self.distance_travelled, "m"])) update_distance_travelled_label = QPushButton("Update") update_distance_travelled_label.clicked.connect( lambda: self.update_value("Distance Travelled", self. distance_travelled)) distance_travelled_layout.addWidget(self.distance_travelled_label) distance_travelled_layout.addWidget(update_distance_travelled_label) history_layout = QHBoxLayout() cardio_history_button = QPushButton("History") cardio_history_button.clicked.connect( lambda: self.show_cardio_history()) self.save_changes_cardio_button = QPushButton("Save Changes") self.save_changes_cardio_button.clicked.connect( lambda: self.add_cardio_entry_to_cardio_history()) history_layout.addWidget(cardio_history_button) history_layout.addWidget(self.save_changes_cardio_button) cardio_notes.addWidget(main_label) cardio_notes.addLayout(preferred_activity_layout) cardio_notes.addLayout(time_spent_layout) cardio_notes.addLayout(distance_travelled_layout) cardio_notes.addLayout(calories_burnt_layout) cardio_notes.addLayout(history_layout) cardio_notes.setSpacing(5) framed_layout = QFrame() framed_layout.setObjectName("graphObj") framed_layout.setFrameStyle(QFrame.Box) framed_layout.setLineWidth(3) framed_layout.setStyleSheet("""#graphObj {color: #322d2d;}""") framed_layout.setLayout(cardio_notes) return framed_layout def update_value(self, to_edit, old_value): fitness_goal = None date = None if not to_edit == "Calories Burnt": if to_edit == "Loss Per Week": fitness_goal = self.user_data["Goal Params"][0] elif to_edit == "Current Weight": date = self.date self.dialog = WeightLossEditDialog(to_edit, old_value, fitness_goal, date) self.dialog.update_label_signal.connect( lambda label_to_update: self.update_weight_loss_label( label_to_update)) self.dialog.update_cardio_notes_signal.connect( lambda value_to_update: self.update_cardio_notes_label( to_edit, value_to_update)) self.dialog.update_graph_signal.connect( lambda signal: self.refresh_graph(signal)) else: self.dialog = CaloriesBurntDialog(to_edit, old_value, self.time_spent, self.distance_travelled, self.preferred_activity, self.current_weight) self.dialog.update_calories_label_signal.connect( lambda value_to_update: self.update_cardio_notes_label( to_edit, value_to_update)) self.dialog.show() @pyqtSlot(bool) def update_weight_loss_label(self, signal): if signal: self.fetch_user_data() self.current_weight_label.setText(" ".join( ["Current Weight:", str(self.current_weight), self.units])) self.weight_goal_label.setText(" ".join( ["Weight Goal:", str(self.goal_weight), self.units])) self.loss_per_week_label.setText(" ".join( ["Loss Per Week:", str(self.loss_per_week), self.units])) @pyqtSlot(str) def update_cardio_notes_label(self, to_edit, value_to_update): if to_edit == "Time Spent": self.time_spent = value_to_update self.time_spent_label.setText(" ".join( ["Time Spent:", str(value_to_update), "min"])) elif to_edit == "Distance Travelled": self.distance_travelled = value_to_update self.distance_travelled_label.setText(" ".join( ["Distance Travelled:", str(value_to_update), "m"])) elif to_edit == "Calories Burnt": self.calories_burnt = value_to_update self.calories_burnt_label.setText(" ".join( ["Calories Burnt", str(value_to_update), "kcal"])) def fetch_user_data(self): self.user_data = self.db_wrapper.fetch_local_user_info() self.current_weight = self.user_data["Weight"] self.goal_weight = self.user_data["Weight Goal"] self.loss_per_week = self.user_data["Goal Params"][1] def show_weight_history(self): self.history = WeightLossHistory() self.history.update_weight_loss_label_signal.connect( lambda signal: self.update_weight_loss_label(signal)) self.history.setGeometry(100, 200, 300, 300) self.history.show() def show_cardio_history(self): self.cardio_history_dialog = CardioHistory() self.cardio_history_dialog.refresh_cardio_labels_signal.connect( lambda signal: self.refresh_cardio_notes(signal)) self.cardio_history_dialog.setGeometry(100, 200, 300, 300) self.cardio_history_dialog.show() @pyqtSlot(bool) def refresh_cardio_notes(self, signal): if signal: self.cardio_history = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "cardio_history")) self.init_cardio_labels() self.time_spent_label.setText(" ".join( ["Time Spent:", self.time_spent, "min"])) self.distance_travelled_label.setText(" ".join( ["Distance Travelled:", self.distance_travelled, "m"])) self.calories_burnt_label.setText(" ".join( ["Calories Burnt:", self.calories_burnt, "kcal"])) def set_new_preferred_activity(self, activity): self.preferred_activity = activity self.preferred_activity_label.setText(" ".join( ["Preferred Activity:", activity])) self.preferred_activity_dropdown.setCurrentText(activity) self.db_wrapper.update_table_column(self.table_name, "preferred_activity", self.preferred_activity) self.init_cardio_labels() self.time_spent_label.setText(" ".join( ["Time Spent:", self.time_spent, "min"])) self.distance_travelled_label.setText(" ".join( ["Distance Travelled:", self.distance_travelled, "m"])) self.calories_burnt_label.setText(" ".join( ["Calories Burnt:", self.calories_burnt, "kcal"])) def init_cardio_labels(self): if len(self.cardio_history[self.date][self.preferred_activity]) > 0: self.today_exercise = self.cardio_history[self.date][ self.preferred_activity][-1] self.time_spent = self.today_exercise["Time Spent"] self.distance_travelled = self.today_exercise["Distance Travelled"] self.calories_burnt = self.today_exercise["Calories Burnt"] else: self.time_spent = "0" self.distance_travelled = "0" self.calories_burnt = "0" def add_date_to_cardio_history(self): activities = ["Running", "Walking", "Cycling", "Swimming"] self.cardio_history[self.date] = {} for activity in activities: self.cardio_history[self.date][activity] = [] cardio_history = json.dumps(self.cardio_history) self.db_wrapper.update_table_column(self.table_name, "cardio_history", cardio_history) def add_cardio_entry_to_cardio_history(self): date = datetime.today().strftime("%d/%m/%Y") new_entry = { "Time Spent": str(self.time_spent), "Distance Travelled": str(self.distance_travelled), "Calories Burnt": str(self.calories_burnt) } self.cardio_history[date][self.preferred_activity].append(new_entry) current_cardio_history = json.dumps(self.cardio_history) self.db_wrapper.update_table_column(self.table_name, "cardio_history", current_cardio_history) def add_date_to_weight_history(self): try: last_entry = list(self.weight_history.values())[-1] self.weight_history[self.date] = last_entry self.db_wrapper.update_table_column( self.table_name, "weight_history", json.dumps(self.weight_history)) except IndexError: # no records pass @pyqtSlot(bool) def refresh_graph(self, signal): if signal: self.weight_history = self.db_wrapper.fetch_local_column( self.table_name, "weight_history") self.replace_graph(str(self.months_combobox.currentText())) def replace_graph(self, month): new_graph = WeightLossGraphCanvas(month, self.current_year, self) new_toolbar = NavigationToolbar(new_graph, self) old_toolbar_reference = self.graph_layout.itemAt(0).widget() old_graph_reference = self.graph_layout.itemAt(1).widget() self.graph_layout.replaceWidget(old_toolbar_reference, new_toolbar) self.graph_layout.replaceWidget(old_graph_reference, new_graph) def change_year_graph(self, year): self.current_year = year self.replace_graph(str(self.months_combobox.currentText())) def change_month_graph(self, month): self.replace_graph(str(month))
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) # Stores all images inside the current image's directory. self.dirImages = [] # Store the current image being displayed. self.currentImage = None self.setupMenuBar() self.setupUi() def setupUi(self): """ Setup the application UI. """ self.resize(QGuiApplication.primaryScreen().availableSize() * 2 / 3) # Instanciate the image viewer. self.imageView = ImageView() # Get the system font size font = QFont() size = font.pointSize() # Increase size. font.setPointSize(size + 2) # Create a label to display the images. self.introLabel = QLabel("Press Ctrl+O to select an image" "\nOr choose a directory by pressing Ctrl+D") self.introLabel.setAlignment(Qt.AlignCenter) self.introLabel.setFont(font) # Create the index area. # Button - Text - Button # A frame to draw a line around the layout. self.indexBox = IndexBox() self.buttonPrevious = IndexButton("Previous") self.buttonPrevious.setEnabled(False) self.buttonPrevious.clicked.connect(self.previousImage) self.labelIndex = QLabel() self.labelIndex.setAlignment(Qt.AlignCenter) self.buttonNext = IndexButton("Next") self.buttonNext.setEnabled(False) self.buttonNext.clicked.connect(self.nextImage) frameLayout = QHBoxLayout() frameLayout.addWidget(self.buttonPrevious) frameLayout.addWidget(self.labelIndex) frameLayout.addWidget(self.buttonNext) self.indexBox.setLayout(frameLayout) # Create and add widgets to the main layout. self.mainLayout = QVBoxLayout() self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.introLabel) self.mainLayout.addWidget(self.indexBox) # Create central widget. centralWidget = QWidget() centralWidget.setLayout(self.mainLayout) self.setCentralWidget(centralWidget) def setupMenuBar(self): """ Setup the application menu bar. """ # Create the menu bar actions. self.createActions() menuBar = self.menuBar() fileMenu = menuBar.addMenu("&File") fileMenu.addAction(self.openFileAct) fileMenu.addAction(self.openDirAct) fileMenu.addSeparator() fileMenu.addAction(self.exitAct) viewMenu = menuBar.addMenu("&View") viewMenu.addAction(self.zoomInAct) viewMenu.addAction(self.zoomOutAct) viewMenu.addSeparator() viewMenu.addAction(self.normalSizeAct) viewMenu.addAction(self.fitToWindowAct) viewMenu.addAction(self.fullscreenAct) def createActions(self): """ Create the actions for the application menu bar. """ """ File menu actions. """ self.openFileAct = QAction("&Open file..", self, shortcut="Ctrl+O") self.openFileAct.setToolTip("Select an image") self.openFileAct.triggered.connect(self.showFileDialog) self.openDirAct = QAction("&Choose directory..", self, shortcut="Ctrl+D") self.openDirAct.setToolTip("Choose a directory instead of a file") self.openDirAct.triggered.connect(self.showDirDialog) self.exitAct = QAction("&Exit", self, shortcut="Ctrl+Q") self.exitAct.setToolTip("Close the application..") self.exitAct.triggered.connect(self.close) """ View menu actions. """ self.zoomInAct = QAction("&Zoom In", self, shortcut="Ctrl++") self.zoomInAct.setToolTip("Zoom in") self.zoomOutAct = QAction("&Zoom Out", self, shortcut="Ctrl+-") self.zoomOutAct.setToolTip("Zoom out") self.normalSizeAct = QAction("&Normal Size", self, shortcut="Ctrl+S") self.normalSizeAct.setToolTip("Reset zoom level") self.normalSizeAct.setEnabled(False) self.fitToWindowAct = QAction("&Fit Window", self, shortcut="Ctrl+F", checkable=True, triggered=self.fitImage) self.fitToWindowAct.setToolTip( "Resize image to fit the current window") self.fullscreenAct = QAction("&Fullscreen Mode", self, shortcut="F11", checkable=True, triggered=self.fullscreen) # Disable actions by default. self.zoomInAct.setEnabled(False) self.zoomOutAct.setEnabled(False) self.normalSizeAct.setEnabled(False) self.fitToWindowAct.setEnabled(False) def showFileDialog(self): """ Open a file dialog that only allows the user to choose image files. Only supports .jpg and .png files for now. """ # Transforms the list of extensions in a string # Something like: *.jpg *.png extensions = "*." + " *.".join(SUPPORTED_EXTENSIONS) # Open file dialog. # Returns a tuple, first element is the selected path. # Second element is the chosen filter. filePath = QFileDialog.getOpenFileName( parent=self, caption="Select an image file.", directory=os.path.expanduser("~"), filter="Image Files ({})".format(extensions), )[0] if not filePath: return self.loadImage(filePath) def showDirDialog(self): """ Open a directory dialog. Also show files, but only directories can be selected. """ path = QFileDialog.getExistingDirectory( parent=self, caption="Choose a directory", directory=os.path.expanduser("~"), options=QFileDialog.DontUseNativeDialog, ) if not path: return # Scan the directory. self.scanDir(path) # Check if directory is empty. if not self.dirImages: QMessageBox.critical(self, "Error!", "No images were found!") return # Load the first image from the directory. self.loadImage(self.dirImages[0]) def loadImage(self, imagePath: str): """ Display image from `imagePath`. """ # Load image. Converts to QPixmap automatically. self.imageView.setImage(imagePath) # Check fit status self.fitImage() # This will run only when the first image is loaded. if self.currentImage is None: # Replace the intro text with the image. self.mainLayout.replaceWidget(self.introLabel, self.imageView) # Enable buttons. They will be hidden/shown later. self.buttonPrevious.setEnabled(True) self.buttonNext.setEnabled(True) # Enable action. self.fitToWindowAct.setEnabled(True) # Store the current image. self.currentImage = imagePath # Scan the current image's directory. self.scanDir(os.path.dirname(self.currentImage)) # Update the index self.updateIndex() def scanDir(self, path: str): """ Scan the image's directory. """ # Stores all files inside the directory. imageDir = QDir(path) imageDir.setFilter(QDir.Files | QDir.NoSymLinks | QDir.Readable) # Add files' absolute path to list. self.dirImages = [ file.absoluteFilePath() for file in imageDir.entryInfoList() if file.suffix() in SUPPORTED_EXTENSIONS ] def updateIndex(self): index = self.dirImages.index(self.currentImage) total = len(self.dirImages) fileName = os.path.basename(self.currentImage) if index == 0: self.buttonPrevious.setHidden(True) self.buttonNext.setHidden(False) elif (index + 1) == total: self.buttonPrevious.setHidden(False) self.buttonNext.setHidden(True) else: self.buttonPrevious.setHidden(False) self.buttonNext.setHidden(False) text = f"{index + 1} of {total} - {fileName}" self.labelIndex.setText(text) def nextImage(self): index = self.dirImages.index(self.currentImage) self.loadImage(self.dirImages[index + 1]) def previousImage(self): index = self.dirImages.index(self.currentImage) self.loadImage(self.dirImages[index - 1]) def fitImage(self): fit = self.fitToWindowAct.isChecked() if fit: self.imageView.fitToWindow() else: self.imageView.showNormal() def fullscreen(self): if not self.isFullScreen(): self.showFullScreen() else: self.showNormal() def resizeEvent(self, event): if self.currentImage is None: event.accept() fit = self.fitToWindowAct.isChecked() if fit: self.imageView.fitToWindow() else: self.imageView.showNormal()
class QWPopupTableCheck(QWidget): """ """ def __init__(self, **kwargs): parent = kwargs.get('parent', None) QWidget.__init__(self, parent) self.kwargs = kwargs self.list2d_out = [] win_title = kwargs.get('win_title', None) if win_title is not None: self.setWindowTitle(win_title) #self.wtab = QWTableOfCheckBoxes(**kwargs) self.wtab = CGWPartitionTable(**kwargs) #self.make_gui_checkbox() self.do_ctrl = kwargs.get('do_ctrl', True) self.do_frame = kwargs.get('do_frame', True) #self.but_update = QPushButton('&Update') #self.but_cancel = QPushButton('&Cancel') self.but_apply = QPushButton('&Apply') #self.but_update.clicked.connect(self.on_but_update) #self.but_cancel.clicked.connect(self.onCancel) self.but_apply.clicked.connect(self.onApply) self.hbox = QHBoxLayout() #self.hbox.addWidget(self.but_update) #self.hbox.addStretch(1) #self.hbox.addWidget(self.but_cancel) self.hbox.addStretch(1) self.hbox.addWidget(self.but_apply) self.vbox = QVBoxLayout() self.vbox.addWidget(self.wtab) self.vbox.addLayout(self.hbox) self.setLayout(self.vbox) self.setIcons() self.set_style() #----------------------------- def set_style(self): #if not self.do_frame: # self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint) styleGray = "background-color: rgb(230, 240, 230); color: rgb(0, 0, 0);" # Gray #styleTest = "background-color: rgb(100, 240, 200); color: rgb(0, 0, 0);" styleDefault = "" self.setStyleSheet(styleDefault) self.layout().setContentsMargins(0, 0, 0, 0) self.setMinimumWidth(100) #self.but_update.setFixedWidth(70) #self.but_cancel.setFixedWidth(70) self.but_apply.setFixedWidth(70) #self.but_update.setStyleSheet(styleGray) #self.but_update.setFocusPolicy(Qt.NoFocus) #self.but_cancel.setFocusPolicy(Qt.NoFocus) #self.but_cancel.setStyleSheet(styleGray) self.but_apply.setStyleSheet(styleGray) self.but_apply.setEnabled(self.do_ctrl) self.but_apply.setFlat(not self.do_ctrl) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.wtab.setFixedHeight(self.wtab.height() + 2) self.setFixedWidth(max(self.wtab.width(), 285) + 2) #self.but_update.setVisible(False) #self.but_cancel.setVisible(False) #self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint) #self.setWindowFlags(Qt.Window | Qt.CustomizeWindowHint) def setIcons(self): try: from psdaq.control_gui.QWIcons import icon icon.set_icons() #self.but_cancel.setIcon(icon.icon_button_cancel) self.but_apply.setIcon(icon.icon_button_ok) except: pass #def on_but_update(self): def update_partition_table(self): logger.debug('update_partition_table') _, list2d = get_platform( ) # [[[True,''], 'test/19670/daq-tst-dev02', 'testClient2b'], ...] logger.debug('list2d\n', list2d) self.kwargs['tableio'] = list2d wtab = CGWPartitionTable(**self.kwargs) self.vbox.replaceWidget(self.wtab, wtab) #self.vbox.removeWidget(self.hbox) #self.vbox.addLayout(self.hbox) self.wtab.close() del self.wtab self.wtab = wtab self.set_style() #def onCancel(self): # logger.debug('onCancel') # self.reject() def onApply(self): logger.debug('onApply') self.list2d_out = self.wtab.fill_output_object() #self.accept() dict_platf, list2d = get_platform( ) # [[[True,''], 'test/19670/daq-tst-dev02', 'testClient2b'], ...] set_platform(dict_platf, self.list2d_out) ## 2019-03-13 caf: If Select->Apply is successful, an Allocate transition should be triggered. ## 2020-07-29 caf: The Allocate transition will update the active detectors file, if necessary. list2d_active = list_active_procs(self.list2d_out) if len(list2d_active) == 0: logger.warning('NO PROCESS SELECTED!') else: daq_control().setState('allocated') def table_out(self): return self.list2d_out
class SongsTable_Container(FFrame): def __init__(self, app, parent=None): super().__init__(parent) self._app = app self.songs_table = None self.img_label = CoverImgLabel(self._app) self.desc_container = DescriptionContainer(self._app) self.info_container = FFrame(parent=self) self.table_control = TableControl(self._app) self._layout = QVBoxLayout(self) self._info_layout = QHBoxLayout(self.info_container) self.setup_ui() def setup_ui(self): self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setSpacing(0) self._info_layout.setContentsMargins(0, 0, 0, 0) self._info_layout.setSpacing(0) self._info_layout.addWidget(self.img_label) self._info_layout.addSpacing(20) self._info_layout.addWidget(self.desc_container) self._layout.addSpacing(10) self._layout.addWidget(self.info_container) self._layout.addSpacing(10) self._layout.addWidget(self.table_control) def set_table(self, songs_table): if self.songs_table: self._layout.replaceWidget(self.songs_table, songs_table) self.songs_table.deleteLater() else: self._layout.addWidget(songs_table) self._layout.addSpacing(10) self.songs_table = songs_table def load_img(self, img_url, img_name): self.info_container.show() event_loop = asyncio.get_event_loop() future = event_loop.create_task( self._app.img_ctl.get(img_url, img_name)) future.add_done_callback(self.set_img) def set_img(self, future): content = future.result() img = QImage() img.loadFromData(content) pixmap = QPixmap(img) if pixmap.isNull(): return None self.img_label.setPixmap( pixmap.scaledToWidth(self.img_label.width(), mode=Qt.SmoothTransformation)) def set_desc(self, desc): self.desc_container.set_html(desc) def hide_info_container(self): self.info_container.hide()
class ColumnEditor(QWidget): def __init__(self): QWidget.__init__(self) self.column = None pal = self.palette() pal.setColor(QPalette.Background, QColor(self.palette().base().color().name()).lighter()) self.setPalette(pal) self.setAutoFillBackground(True) self.layout = QVBoxLayout() self.layout.setAlignment(Qt.AlignTop) self.setLayout(self.layout) self.setAcceptDrops(True) ee = ElementEditor() self.layout.addWidget(ee, 0, Qt.AlignTop) ee.elementEnabled.connect(self.addElement) ee.elementDragged.connect(self.addElement) # connect(ee, SIGNAL(elementCopied(ElementEditor*)), this, SLOT(copyElement(ElementEditor*))); def addElement(self): ee = ElementEditor() self.layout.addWidget(ee, 0, Qt.AlignTop) ce = self.getContentEditor() if ce: ce.editChanged("Add Element") ee.elementEnabled.connect(self.addElement) ee.elementDragged.connect(self.addElement) # connect(ee, SIGNAL(elementCopied(ElementEditor*)), this, SLOT(copyElement(ElementEditor*))); def addElementEditor(self, ee): self.layout.insertWidget(self.layout.count() - 1, ee, 0, Qt.AlignTop) ee.elementEnabled.connect(self.addElement) ee.elementDragged.connect(self.addElement) #connect(ee, SIGNAL(elementCopied(ElementEditor*)), this, SLOT(copyElement(ElementEditor*))); def getContentEditor(self): from widgets.pageeditor import PageEditor from widgets.roweditor import RowEditor from widgets.sectioneditor import SectionEditor re = self.parentWidget() if isinstance(re, RowEditor): se = re.parentWidget() if isinstance(se, SectionEditor): pe = se.parentWidget() if isinstance(pe, PageEditor): sa = pe.parentWidget() if sa: vp = sa.parentWidget() if vp: cee = vp.parentWidget() if cee: return cee return None def load(self, column): self.column = column for item in self.column.items: ee = ElementEditor() ee.setMode(Mode.ENABLED) ee.setContent(item) ee.elementEnabled.connect(self.addElement) ee.elementDragged.connect(self.addElement) #connect(ee, SIGNAL(elementCopied(ElementEditor*)), this, SLOT(copyElement(ElementEditor*))); self.layout.insertWidget(self.layout.count() - 1, ee, 0, Qt.AlignTop) def dragEnterEvent(self, event): myData = event.mimeData() if myData: ee = myData.getData() if isinstance(ee, ElementEditor): for i in range(self.layout.count()): editor = self.layout.itemAt(i).widget() if isinstance(editor, ElementEditor) and editor.mode == Mode.EMPTY: editor.setMode(Mode.DROPZONE) break event.accept() else: event.ignore() else: event.ignore() def dragLeaveEvent(self, event): for i in range(self.layout.count()): editor = self.layout.itemAt(i).widget() if isinstance(editor, ElementEditor) and editor.mode == Mode.DROPZONE: # put editor to the end of the list editor.setMode(Mode.EMPTY) self.layout.removeWidget(editor) self.layout.addWidget(editor) break event.accept() def dragMoveEvent(self, event): myData = event.mimeData() if myData: ee = myData.getData() if isinstance(ee, ElementEditor): row = event.pos().y() / 50 #+ self.layout.margin()) for i in range(self.layout.count()): editor = self.layout.itemAt(i).widget() if isinstance( editor, ElementEditor) and editor.mode == Mode.DROPZONE: if i != row: # put dropzone under mouse pointer self.layout.insertWidget(row, editor) break event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() else: event.ignore() def dropEvent(self, event): myData = event.mimeData() if myData: ee = myData.getData() if isinstance(ee, ElementEditor): for i in range(self.layout.count()): dz = self.layout.itemAt(i).widget() if isinstance(dz, ElementEditor) and dz.mode == Mode.DROPZONE: # remove widget if it belongs to this layout self.layout.removeWidget(ee) # replace dropzone with dragged element self.layout.replaceWidget(dz, ee) new_pos = i # and put dropzone to the end of the list dz.setMode(Mode.EMPTY) self.layout.removeWidget(dz) self.layout.addWidget(dz) break ee.dropped() ee.show() ee.elementEnabled.disconnect() ee.elementDragged.disconnect() # ee.copied.disconnect(self.copyElement) ce = self.getContentEditor() if ce: myData.source_list.remove(ee.content) self.column.insertElement(ee.content, new_pos) ce.editChanged("Move Element") ee.elementEnabled.connect(self.addElement) ee.elementDragged.connect(self.addElement) # ee.elementCopied.connectself.copyElement) event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() else: event.ignore() def removeElement(self, content): self.column._items.remove(content)
class EphemerisDialog(QDialog): def __init__(self, app: EphemerisApp, parent=None): super(EphemerisDialog, self).__init__(parent) self.offset = QPoint() self.ephemeris = app self.app = app.app_ctx self._header_title = 'E P H E M E R I S' self.google_service = GoogleService(self.app) self._main_layout = QVBoxLayout() self._main_layout.addLayout(self._create_head()) self._bottom_btn = QPushButton() self._current_view = self._get_start_view() self._main_layout.addWidget(self._current_view) self._main_layout.addWidget(self._bottom_btn) self.setLayout(self._main_layout) self.setFixedWidth(230) self._set_flags() def switch_current_view(self, new: EphemerisGroupBox): self._main_layout.replaceWidget(self._current_view, new) self._current_view.deleteLater() self._current_view = new self._switch_button(new) self.refresh() self.raise_() self.activateWindow() def refresh(self): self.setVisible(False) self.setVisible(True) def _switch_button(self, group): self._bottom_btn.setText(group.button_label) self._bottom_btn.setIcon(QIcon() if group.button_icon is None else group.button_icon) try: self._bottom_btn.disconnect() except(): pass self._bottom_btn.clicked.connect(group.button_click) self._bottom_btn.setFocus() def _get_start_view(self): if not self.google_service.is_token_exists(): group = LoginGroupBox(self) self._switch_button(group) return group else: self.google_service.prepare_credentials() self.google_service.build_resource() group = InputGroupBox(self) self._switch_button(group) return group def _set_flags(self): self.setWindowFlag(Qt.WindowStaysOnTopHint) self.setWindowFlag(Qt.FramelessWindowHint) def _create_head(self): logo = QLabel() logo.setPixmap(get_QPixmap(self.app, 'logo_transparent_tiny.png')) label = QLabel(self._header_title) logo.setBuddy(label) header = QHBoxLayout() self._setup_header_widgets() header.addWidget(logo) header.addWidget(label) header.addStretch(2) header.addWidget(self.cog) return header def _setup_header_widgets(self): self.cog = PicButton(self.app, 'cog.png') self.cog.setContextMenuPolicy(Qt.CustomContextMenu) self.menu = QMenu() self.quit_a = QAction("Quit") self.pin_a = QAction("Pin") self.menu.addAction(self.pin_a) self.menu.addSeparator() self.menu.addAction(self.quit_a) self.pin_a.triggered.connect(self._on_pin_click) self.quit_a.triggered.connect(self.app.app.quit) self.cog.setMenu(self.menu) def _on_cog_click(self, point): self.menu.exec_(self.cog.mapToGlobal(point)) def _on_pin_click(self): self.ephemeris.is_pinned = not self.ephemeris.is_pinned text = 'Unpin' if self.ephemeris.is_pinned else 'Pin' self.pin_a.setText(text) print(f'set to {self.ephemeris.is_pinned}') self.show() def mousePressEvent(self, event): self.offset = event.pos() def mouseMoveEvent(self, event): x = event.globalX() y = event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x - x_w, y - y_w)
class MainWindow(QWidget): def __init__(self, windowsManager, parent=None): super().__init__(parent) self.windowsManager = windowsManager # 툴바 레이아웃. 상단에 단어 정렬, 설정, 외우기모드 시작 버튼 등 # 조작할 수 있는 것들을 모아둠. toolbarLayout = QGridLayout() memorizeStartBt = self.windowsManager.qButtonMaker( "Memorize Start", self.buttonClicked, None, (QSizePolicy.Expanding, QSizePolicy.Expanding)) toolbarLayout.addWidget(memorizeStartBt, 0, 0, 3, 1) self.wordStandardCB = QComboBox() self.wordStandardCBStarted = False self.wordStandardCB.currentIndexChanged.connect( self.wordStandardCBChanged) self.wordStandardCB.addItems(["모두", "집중 단어만", "집중 단어 아닌것만"]) self.sortStandardCB = QComboBox() self.sortStandardCBStarted = False self.sortStandardCB.currentIndexChanged.connect( self.sortStandardCBChanged) self.sortStandardCB.addItems( ["저장순", "영어 오름차순", "영어 내림차순", "한글 오름차순", "한글 내림차순"]) settingBt = self.windowsManager.qButtonMaker( "설정", self.buttonClicked, None, (QSizePolicy.Expanding, QSizePolicy.Expanding)) toolbarLayout.addWidget(self.wordStandardCB, 0, 1) toolbarLayout.addWidget(self.sortStandardCB, 1, 1) toolbarLayout.addWidget(settingBt, 2, 1) # 단어 레이아웃. 단어들 보여줌. self.focusedWordHint = QCheckBox() self.focusedWordHint.setText("= 집중 단어") self.focusedWordHint.setChecked(True) self.focusedWordHint.setDisabled(True) self.wordListLayout = QVBoxLayout() self.wordsScrollArea = QScrollArea() self.wordListLayout.addWidget(self.wordsScrollArea) self.updateWordListUI() # 단어 추가 레이아웃. wordAddLayout = QHBoxLayout() wordAddLayoutLeft = QGridLayout() sz = (200, 90) self.wordAddEnTE = self.windowsManager.qTextWidgetSetter( QTextEdit(), "", False, Qt.AlignLeft, sz) self.wordAddKoTE = self.windowsManager.qTextWidgetSetter( QTextEdit(), "", False, Qt.AlignLeft, sz) wordAddLayoutLeft.addWidget(QLabel("영어"), 0, 0) wordAddLayoutLeft.addWidget(self.wordAddEnTE, 1, 0) wordAddLayoutLeft.addWidget(QLabel("한글"), 0, 1) wordAddLayoutLeft.addWidget(self.wordAddKoTE, 1, 1) wordAddLayout.addLayout(wordAddLayoutLeft) wordAddLayoutRight = QGridLayout() wordAddBt = self.windowsManager.qButtonMaker( "추가", self.buttonClicked, None, (QSizePolicy.Expanding, QSizePolicy.Expanding)) wordDeleteBt = self.windowsManager.qButtonMaker( "삭제", self.buttonClicked, None, (QSizePolicy.Expanding, QSizePolicy.Expanding)) wordStringClearBt = self.windowsManager.qButtonMaker( "취소", self.buttonClicked, None, (QSizePolicy.Expanding, QSizePolicy.Expanding)) wordAddLayoutRight.addWidget(wordAddBt, 0, 0) wordAddLayoutRight.addWidget(wordDeleteBt, 2, 0) wordAddLayoutRight.addWidget(wordStringClearBt, 3, 0) wordAddLayout.addLayout(wordAddLayoutRight) wordAddLayout.setSizeConstraint(QLayout.SetFixedSize) mainLayout = QGridLayout() mainLayout.setSizeConstraint(QLayout.SetFixedSize) mainLayout.addLayout(toolbarLayout, 0, 0) mainLayout.addLayout(self.wordListLayout, 1, 0) mainLayout.addLayout(wordAddLayout, 2, 0) self.setLayout(mainLayout) self.setWindowTitle('Memorize Words') def showWindow(self): self.show() self.move(500, 100) def wordAdd(self): en, ko = self.stripWordAddTextEdits() if en == "" and ko == "": return elif en == "": self.MessagingError("이름이 입력되지 않았습니다.") return elif ko == "": self.MessagingError("뜻이 입력되지 않았습니다.") return wordStandard = self.wordStandardCB.currentText() isFocused = False if wordStandard == "모두": wordStandardJudge = self.wordStandardJudgeWhoWantAll elif wordStandard == "집중 단어만": wordStandardJudge = self.wordStandardJudgeWhoWantFocused isFocused = True elif wordStandard == "집중 단어 아닌것만": wordStandardJudge = self.wordStandardJudgeWhoWantNotFocused else: self.MessagingError("알수 없는 오류가 발생했습니다: wordStandard에 \'" + wordStandard + "\'이 없음") return word = Word(en, ko, (isFocused, self.windowsManager.dataManager)) self.windowsManager.dataManager.wordAdd(word) self.wordAddTextClear() self.updateListedWords() def stripWordAddTextEdits(self): en = self.wordAddEnTE.toPlainText().strip() ko = self.wordAddKoTE.toPlainText().strip() self.wordAddEnTE.setText(en) self.wordAddKoTE.setText(ko) return en, ko def wordAddTextClear(self): self.wordAddEnTE.clear() self.wordAddKoTE.clear() def wordDeleteButtonClicked(self): en, ko = self.stripWordAddTextEdits() enEmpty = False koEmpty = False if en == "": enEmpty = True if ko == "": koEmpty = True if enEmpty and koEmpty: # 아무 것도 안적은 상태라면 아무 행동도 하지 않음. return if not enEmpty and not koEmpty: # 둘다 적혀 있다면, 두 개가 가리키는 영단어가 # 같은지 확인, 같다면 지우고 다르다면 에러 메시지. ws_en = self.findWordsAtNowListedWordsByEn(en) ws_ko = self.findWordsAtNowListedWordsByKo(ko) # 단어가 없다면 에러 메시지. if len(ws_en) == 0 or len(ws_ko) == 0: self.MessagingError("\'" + en + " " + ko + "\'는 없는 단어입니다!") return willDelete = [] for w in ws_en: if w in ws_ko: willDelete.append(w) if len(willDelete) == 0: self.MessagingError("단어의 이름과 뜻이 다릅니다!") else: for w in willDelete: self.wordDelete(w) else: if not enEmpty: # 영어만 채워져 있다면, 같은 이름의 모든 단어 삭제 ws_en = self.findWordsAtNowListedWordsByEn(en) if len(ws_en) == 0: self.MessagingError("\'" + en + "\'이 현재 리스트에 없습니다!") else: for w in ws_en: self.wordDelete(w) else: # 한글만 채워져 있다면, 같은 뜻의 모든 단어 삭제 ws_ko = self.findWordsAtNowListedWordsByKo(ko) if len(ws_ko) == 0: self.MessagingError("\'" + ko + "\'이 현재 리스트에 없습니다!") else: for w in ws_ko: self.wordDelete(w) def wordDelete(self, word): en, ko = word.getStrings() print("Delete", en, ko) try: self.windowsManager.getNowListedWords().remove(word) self.windowsManager.dataManager.wordDelete(word) self.MessagingSuccess('\'' + en + ' ' + ko + "\'가 삭제되었습니다.") self.wordAddTextClear() except: self.MessagingError("없는 단어입니다.") self.updateListedWords() def MessagingSuccess(self, content): QMessageBox.about(self, "Success", content) def MessagingError(self, content): QMessageBox.about(self, "Error", content) def findWordsAtNowListedWordsByEn(self, en): ws = [] for w in self.windowsManager.getNowListedWords(): w_en, w_ko = w.getStrings() if w_en == en: ws.append(w) return ws def findWordsAtNowListedWordsByKo(self, ko): ws = [] for w in self.windowsManager.getNowListedWords(): w_en, w_ko = w.getStrings() if w_ko == ko: ws.append(w) return ws def wordStandardCBChanged(self, i): if not self.wordStandardCBStarted: self.wordStandardCBStarted = True return print("wordStandardCB current", self.wordStandardCB.currentText()) self.updateListedWords() def sortStandardCBChanged(self, i): if not self.sortStandardCBStarted: self.sortStandardCBStarted = True return print("sortStandardCBChanged", i) self.updateListedWords() def updateListedWords(self): wordStandard = self.wordStandardCB.currentText() if wordStandard == "모두": wordStandardJudge = self.wordStandardJudgeWhoWantAll elif wordStandard == "집중 단어만": wordStandardJudge = self.wordStandardJudgeWhoWantFocused elif wordStandard == "집중 단어 아닌것만": wordStandardJudge = self.wordStandardJudgeWhoWantNotFocused else: print("wordStandard가 존재하지 않는 값입니다!:", wordStandard) return sortStandard = self.sortStandardCB.currentText() words = self.windowsManager.getAllWords() judgedWords = [] for w in words: if wordStandardJudge(w): judgedWords.append(w) if sortStandard == "저장순": pass elif sortStandard == "영어 오름차순": judgedWords = sorted( judgedWords, key=lambda x: self.sortStandardJudgeWhoWantEn(x), reverse=False) elif sortStandard == "영어 내림차순": judgedWords = sorted( judgedWords, key=lambda x: self.sortStandardJudgeWhoWantEn(x), reverse=True) elif sortStandard == "한글 오름차순": judgedWords = sorted( judgedWords, key=lambda x: self.sortStandardJudgeWhoWantKo(x), reverse=False) elif sortStandard == "한글 내림차순": judgedWords = sorted( judgedWords, key=lambda x: self.sortStandardJudgeWhoWantKo(x), reverse=True) else: print("sortStandard가 존재하지 않는 값입니다!:", sortStandard) return self.windowsManager.setNowListedWords(judgedWords) self.updateWordListUI() def wordStandardJudgeWhoWantAll(self, word): return True def wordStandardJudgeWhoWantFocused(self, word): return word.getIsFocusing() def wordStandardJudgeWhoWantNotFocused(self, word): return not word.getIsFocusing() def sortStandardJudgeWhoWantEn(self, word): en, ko = word.getStrings() return en def sortStandardJudgeWhoWantKo(self, word): en, ko = word.getStrings() return ko def updateWordListUI(self): wordsLayout = QVBoxLayout() wordsLayout.addWidget(self.focusedWordHint) self.focusedCheckboxWithWord = {} for w in self.windowsManager.getNowListedWords(): oneWordLayout = QHBoxLayout() cb = QCheckBox() cb.setChecked(w.getIsFocusing()) en, ko = w.getStrings() wdEn = self.windowsManager.qTextWidgetSetter( QTextEdit(), en, True, Qt.AlignLeft, None, (QSizePolicy.Expanding, QSizePolicy.Fixed)) wdKo = self.windowsManager.qTextWidgetSetter( QTextEdit(), ko, True, Qt.AlignLeft, None, (QSizePolicy.Expanding, QSizePolicy.Fixed)) wdEn.setFixedHeight(55) wdKo.setFixedHeight(55) wdEn.selectionChanged.connect(self.wordEnClicked) wdKo.selectionChanged.connect(self.wordKoClicked) cb.clicked.connect(self.focusedCheckboxClicked) oneWordLayout.addWidget(cb) oneWordLayout.addWidget(wdEn) oneWordLayout.addWidget(wdKo) wordsLayout.addLayout(oneWordLayout) self.focusedCheckboxWithWord[cb] = w wordsLayout.addStretch() groupBox = QGroupBox() groupBox.setLayout(wordsLayout) wordsScrollAreaNew = QScrollArea() wordsScrollAreaNew.setWidget(groupBox) wordsScrollAreaNew.setWidgetResizable(True) wordsScrollAreaNew.setFixedSize(550, 550) self.wordListLayout.replaceWidget(self.wordsScrollArea, wordsScrollAreaNew) self.wordsScrollArea = wordsScrollAreaNew def focusedCheckboxClicked(self, val): word = self.focusedCheckboxWithWord[self.sender()] en, ko = word.getStrings() print("Set Focused", val, en, ko) word.setIsFocusing(val, self.windowsManager.dataManager) self.updateListedWords() def buttonClicked(self): bt = self.sender().text() if bt == "Memorize Start": self.windowsManager.memorizeModeStart() elif bt == "추가": self.wordAdd() elif bt == "삭제": self.wordDeleteButtonClicked() elif bt == "취소": self.wordAddTextClear() elif bt == "설정": self.windowsManager.settingWindow.show() def wordEnClicked(self): txt = self.sender().toPlainText() self.wordAddEnTE.setText(txt) def wordKoClicked(self): txt = self.sender().toPlainText() self.wordAddKoTE.setText(txt)
class MainPanel(QWidget): def __init__(self, parent): super().__init__(parent) self.db_wrapper = DatabaseWrapper() self.table_name = "Compound Exercises" self.setStyleSheet(""" QWidget{ color:#c7c7c7; font-weight: bold; } QPushButton{ background-color: rgba(0, 0, 0, 0); border: 1px solid; font-size: 18px; font-weight: bold; border-color: #808080; min-height: 28px; white-space:nowrap; text-align: left; padding-left: 5%; font-family: Montserrat; } QPushButton:hover:!pressed{ border: 2px solid; border-color: #747474; } QPushButton:pressed{ border: 2px solid; background-color: #323232; border-color: #6C6C6C; } QComboBox{ border-radius: 4px; font-size: 18px; font-weight: bold; white-space:nowrap; text-align: left; padding-left: 5%; font-family: Montserrat; min-height: 28px; background-color: #440D0F; } QComboBox:down-arrow{ width: 0px; height: 0px; background: #d3d3d3; opacity:0 } QComboBox:drop-down{ background-color: #440D0F; border: 0px; opacity:0; border-radius: 0px; width: 0px; height: 0px; } QComboBox:hover:!pressed{ background-color: #5D1A1D; } QComboBox:pressed{ background-color: #551812; } """) self.current_year = str(datetime.now().year) self.db_wrapper.create_local_table(self.table_name) if self.db_wrapper.local_table_is_empty(self.table_name): self.db_wrapper.insert_default_values(self.table_name) self.units = "kg" if self.db_wrapper.fetch_local_column( "Users", "units") == "metric" else "lb" big_lifts_units = "kg" if self.db_wrapper.fetch_local_column( self.table_name, "units") == "metric" else "lb" one_rep_maxes = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "one_rep_maxes")) lifts_for_reps = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "lifts_for_reps")) self.rm_history = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "rm_history")) if not self.current_year in self.rm_history: self.add_year_to_rm_history(self.current_year) self.rm_history = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "rm_history")) if self.units != big_lifts_units: units_name = "metric" if self.units == "kg" else "imperial" self.db_wrapper.update_table_column(self.table_name, "units", units_name) if units_name == "metric": for exercise, weight in one_rep_maxes.items(): one_rep_maxes[exercise] = str(pounds_to_kg(weight)) for exercise, reps_and_weight in lifts_for_reps.items(): lifts_for_reps[exercise] = [ reps_and_weight[0], str(pounds_to_kg(reps_and_weight[1])) ] elif units_name == "imperial": for exercise, weight in one_rep_maxes.items(): one_rep_maxes[exercise] = str(kg_to_pounds(weight)) for exercise, reps_and_weight in lifts_for_reps.items(): lifts_for_reps[exercise] = [ reps_and_weight[0], str(kg_to_pounds(reps_and_weight[1])) ] for year in self.rm_history: for month in self.rm_history[year]: for exercise_type in list(self.rm_history[year][month]): for exercise in list( self.rm_history[year][month][exercise_type]): for i, weight in enumerate( self.rm_history[year][month][exercise_type] [exercise]): if units_name == "imperial": self.rm_history[year][month][ exercise_type][exercise][i] = str( kg_to_pounds(weight)) elif units_name == "metric": self.rm_history[year][month][ exercise_type][exercise][i] = str( pounds_to_kg(weight)) self.db_wrapper.update_table_column(self.table_name, "one_rep_maxes", one_rep_maxes) self.db_wrapper.update_table_column(self.table_name, "lifts_for_reps", lifts_for_reps) self.convert_lift_history_weight(self.units) self.one_RM = [[lift, " ".join([weight, self.units])] for lift, weight in one_rep_maxes.items()] self.lifts_reps = [[lift, " ".join(["x".join(weight), self.units])] for lift, weight in lifts_for_reps.items()] self.lift_history_window = LiftHistory() self.lift_history_window.setGeometry(100, 200, 300, 300) self.plists_window = PreferredLifts() self.plists_window.change_lifts_signal.connect( self.changed_preferred_lifts) self.update_1RM_window = Update1RMWindow() self.update_1RM_window.change_1RM_lifts_signal.connect( self.changed_1RM_lifts) self.update_1RM_window.history_signal.connect( lambda signal: self.lift_history_window.create_history(signal)) self.update_1RM_window.update_graph_signal.connect( lambda signal: self.refresh_graph(signal)) self.lifts_for_reps = UpdateLiftsForRepsWindow() self.lifts_for_reps.change_lifts_for_reps_signal.connect( self.changed_lifts_for_reps) self.lifts_for_reps.history_signal.connect( lambda signal: self.lift_history_window.create_history(signal)) self.preferred_lifts = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "preferred_lifts")) self.one_rep_maxes = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "one_rep_maxes")) self.create_panel() def create_panel(self): main_panel_grid = QGridLayout() main_panel_grid.addLayout(self.description(), 0, 0, 1, 1) main_panel_grid.addWidget(self.create_time_graph(), 1, 0, 4, 1) main_panel_grid.addLayout(self.create_bottom_layout(), 5, 0, 3, 1) main_panel_grid.addLayout(self.create_function_buttons(), 8, 0, 1, 1) self.setLayout(main_panel_grid) def description(self): panel_description = QVBoxLayout() desc_font = QFont("Montserrat", 12) description_label = QLabel( "Keep notes and track progress of your preferred big lifts here.", self) description_label.setFont(desc_font) description_label.setFixedHeight(20) panel_description.addWidget(description_label) return panel_description def create_time_graph(self): self.graph_layout = QVBoxLayout() graph = OneRMGraphCanvas("Horizontal Press", self.rm_history, self.current_year, self) combobox_layout = QHBoxLayout() self.lifts_combobox = QComboBox(self) self.lifts_combobox.addItems(list(self.preferred_lifts.values())) self.lifts_combobox.currentTextChanged.connect( lambda lift: self.change_exercise_graph(lift)) self.change_year_combobox = QComboBox(self) self.change_year_combobox.addItems(list(self.rm_history.keys())) self.change_year_combobox.setCurrentText(self.current_year) self.change_year_combobox.currentTextChanged.connect( lambda year: self.change_graph_year(year)) combobox_layout.addWidget(self.change_year_combobox) combobox_layout.addWidget(self.lifts_combobox) toolbar = NavigationToolbar(graph, self) toolbar.setStyleSheet("background-color: white;") self.graph_layout.addWidget(toolbar) self.graph_layout.addWidget(graph) self.graph_layout.addLayout(combobox_layout) framed_graph = QFrame(self) framed_graph.setFrameStyle(QFrame.Box) framed_graph.setLineWidth(3) framed_graph.setLayout(self.graph_layout) return framed_graph def create_bottom_layout(self): bottom_layout = QHBoxLayout() bottom_layout.addWidget(self.create_one_rep_max()) bottom_layout.addWidget(self.create_lifts_for_reps()) return bottom_layout def create_one_rep_max(self): orm_panel = QVBoxLayout() main_label = QLabel("One Rep Max") main_label.setFont(QFont("Ariel", 18, weight=QFont.Bold)) self.horizontal_press_label_ORM = QLabel(": ".join(self.one_RM[0])) self.horizontal_press_label_ORM.setFont(QFont("Ariel", 10)) self.floor_pull_label_ORM = QLabel(": ".join(self.one_RM[1])) self.floor_pull_label_ORM.setFont(QFont("Ariel", 10)) self.squat_label_ORM = QLabel(": ".join(self.one_RM[2])) self.squat_label_ORM.setFont(QFont("Ariel", 10)) self.vertical_press_label_ORM = QLabel(": ".join(self.one_RM[3])) self.vertical_press_label_ORM.setFont(QFont("Ariel", 10)) orm_buttons = QHBoxLayout() update_button = QPushButton("Update") update_button.clicked.connect(lambda: self.update_1RM_window.show()) clear_button = QPushButton("Clear") clear_button.clicked.connect(lambda: self.clear_one_rep_maxes()) orm_buttons.addWidget(update_button) orm_buttons.addWidget(clear_button) orm_panel.addWidget(main_label) orm_panel.addWidget(self.horizontal_press_label_ORM) orm_panel.addWidget(self.floor_pull_label_ORM) orm_panel.addWidget(self.squat_label_ORM) orm_panel.addWidget(self.vertical_press_label_ORM) orm_panel.addLayout(orm_buttons) orm_panel.setSpacing(5) framed_layout = QFrame() framed_layout.setObjectName("graphObj") framed_layout.setFrameStyle(QFrame.Box) framed_layout.setLineWidth(3) framed_layout.setStyleSheet("""#graphObj {color: #322d2d;}""") framed_layout.setLayout(orm_panel) return framed_layout def create_lifts_for_reps(self): reps_panel = QVBoxLayout() main_label = QLabel("Lifts For Reps") main_label.setFont(QFont("Ariel", 18, weight=QFont.Bold)) self.horizontal_press_label_reps = QLabel(": ".join( self.lifts_reps[0])) self.horizontal_press_label_reps.setFont(QFont("Ariel", 10)) self.floor_pull_label_reps = QLabel(": ".join(self.lifts_reps[1])) self.floor_pull_label_reps.setFont(QFont("Ariel", 10)) self.squat_label_reps = QLabel(": ".join(self.lifts_reps[2])) self.squat_label_reps.setFont(QFont("Ariel", 10)) self.vertical_press_label_reps = QLabel(": ".join(self.lifts_reps[3])) self.vertical_press_label_reps.setFont(QFont("Ariel", 10)) reps_buttons = QHBoxLayout() update_button = QPushButton("Update") update_button.clicked.connect(lambda: self.lifts_for_reps.show()) clear_button = QPushButton("Clear") clear_button.clicked.connect(lambda: self.clear_lifts_for_reps()) reps_buttons.addWidget(update_button) reps_buttons.addWidget(clear_button) reps_panel.addWidget(main_label) reps_panel.addWidget(self.horizontal_press_label_reps) reps_panel.addWidget(self.floor_pull_label_reps) reps_panel.addWidget(self.squat_label_reps) reps_panel.addWidget(self.vertical_press_label_reps) reps_panel.addLayout(reps_buttons) framed_layout = QFrame() framed_layout.setObjectName("graphObj") framed_layout.setFrameStyle(QFrame.Box) framed_layout.setLineWidth(3) framed_layout.setStyleSheet("""#graphObj {color: #322d2d;}""") framed_layout.setLayout(reps_panel) return framed_layout def create_function_buttons(self): buttons_panel = QHBoxLayout() lift_history_button = QPushButton() lift_history_button.setText("Lift History") lift_history_button.clicked.connect( lambda: self.lift_history_window.show()) preferred_lists_button = QPushButton() preferred_lists_button.setText("Preferred Lifts") preferred_lists_button.clicked.connect( lambda: self.plists_window.show()) buttons_panel.addWidget(lift_history_button) buttons_panel.addWidget(preferred_lists_button) return buttons_panel @pyqtSlot(bool) def changed_preferred_lifts(self, changed): if changed: self.preferred_lifts = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "preferred_lifts")) parsed_lifts = list(self.preferred_lifts.values()) one_RM_labels = [ self.horizontal_press_label_ORM, self.floor_pull_label_ORM, self.squat_label_ORM, self.vertical_press_label_ORM ] lifts_for_reps_labels = [ self.horizontal_press_label_reps, self.floor_pull_label_reps, self.squat_label_reps, self.vertical_press_label_reps ] for i, label in enumerate(one_RM_labels): label_text = label.text().split(":") label_text[0] = parsed_lifts[i] label.setText(": ".join(label_text)) for i, label in enumerate(lifts_for_reps_labels): label_text = label.text().split(":") label_text[0] = parsed_lifts[i] label.setText(": ".join(label_text)) self.refresh_graph(True) @pyqtSlot(bool) def changed_1RM_lifts(self, changed): if changed: fetch_weight = list( json.loads( self.db_wrapper.fetch_local_column( self.table_name, "one_rep_maxes")).values()) self.set_1RM_labels_text(fetch_weight) @pyqtSlot(bool) def changed_lifts_for_reps(self, changed): if changed: fetch_reps_and_weight = list( json.loads( self.db_wrapper.fetch_local_column( self.table_name, "lifts_for_reps")).values()) self.set_lifts_for_reps_labels_text(fetch_reps_and_weight) def set_lifts_for_reps_labels_text(self, text): lifts_for_reps_labels = [ self.horizontal_press_label_reps, self.floor_pull_label_reps, self.squat_label_reps, self.vertical_press_label_reps ] for i, label in enumerate(lifts_for_reps_labels): label_text = label.text().split(": ") label_text[1] = " ".join(["x".join(text[i]), self.units]) label.setText(": ".join(label_text)) def set_1RM_labels_text(self, text): one_RM_labels = [ self.horizontal_press_label_ORM, self.floor_pull_label_ORM, self.squat_label_ORM, self.vertical_press_label_ORM ] for i, label in enumerate(one_RM_labels): label_text = label.text().split(": ") label_text[1] = " ".join([text[i], self.units]) label.setText(": ".join(label_text)) def clear_one_rep_maxes(self): for exercise, value in self.one_rep_maxes.items(): self.one_rep_maxes[exercise] = "0" self.db_wrapper.update_table_column(self.table_name, "one_rep_maxes", self.one_rep_maxes) self.set_1RM_labels_text(list(self.one_rep_maxes.values())) self.update_1RM_window.set_line_edit_values() def clear_lifts_for_reps(self): lifts_for_reps = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "lifts_for_reps")) for exercise in lifts_for_reps: lifts_for_reps[exercise] = ["0", "0"] self.db_wrapper.update_table_column(self.table_name, "lifts_for_reps", lifts_for_reps) self.set_lifts_for_reps_labels_text(list(lifts_for_reps.values())) self.lifts_for_reps.set_line_edit_values() def replace_graph(self, lift_type): new_graph = OneRMGraphCanvas(lift_type, self.rm_history, self.current_year, self) new_toolbar = NavigationToolbar(new_graph, self) new_toolbar.setStyleSheet("background-color: white;") old_toolbar_reference = self.graph_layout.itemAt(0).widget() old_graph_reference = self.graph_layout.itemAt(1).widget() self.graph_layout.replaceWidget(old_toolbar_reference, new_toolbar) self.graph_layout.replaceWidget(old_graph_reference, new_graph) old_toolbar_reference.deleteLater() old_graph_reference.deleteLater() def change_exercise_graph(self, exercise_name): lift_type = None for l_type, exercise in self.preferred_lifts.items(): if exercise == exercise_name: lift_type = l_type self.replace_graph(lift_type) def change_graph_year(self, year): self.current_year = year lift_type = None for l_type, exercise in self.preferred_lifts.items(): if exercise == str(self.lifts_combobox.currentText()): lift_type = l_type self.replace_graph(lift_type) self.change_year_combobox.setCurrentText(self.current_year) @pyqtSlot(bool) def refresh_graph(self, signal): if signal: self.rm_history = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "rm_history")) lift_type = None for l_type, exercise in self.preferred_lifts.items(): if exercise == str(self.lifts_combobox.currentText()): lift_type = l_type self.replace_graph(lift_type) def convert_lift_history_weight(self, convert_to_units): try: lift_history = json.loads( self.db_wrapper.fetch_local_column(self.table_name, "lift_history")) except TypeError: # lift history is empty return if convert_to_units == "kg": for lift in lift_history: if isinstance( lift[1], list ): # second element of history entry is list, it is lifts_for_reps entry lift[1][1] = str(pounds_to_kg(float(lift[1][1]))) else: lift[1] = str(pounds_to_kg(float(lift[1]))) elif convert_to_units == "lb": for lift in lift_history: if isinstance(lift[1], list): lift[1][1] = str(kg_to_pounds(float(lift[1][1]))) else: lift[1] = str(kg_to_pounds(float(lift[1]))) lift_history = json.dumps(lift_history) self.db_wrapper.update_table_column(self.table_name, "lift_history", lift_history, convert_lift_history_units=True) def add_year_to_rm_history(self, year): new_year = {} for month in self.db_wrapper.months: exercises_dict = {} for lift_type in self.preferred_lifts: exercises_dict[lift_type] = { self.preferred_lifts[lift_type]: [] } new_year[month] = exercises_dict self.rm_history[str(year)] = new_year self.rm_history = json.dumps(self.rm_history) self.db_wrapper.update_table_column(self.table_name, "rm_history", self.rm_history)
class Win(QMainWindow): def __init__(self, *args, **kwargs): super(Win, self).__init__(*args, **kwargs) cont = QWidget() self.setCentralWidget(cont) self.lay = QVBoxLayout() cont.setLayout(self.lay) self.le = QLineEdit() self.lay.addWidget(self.le) self.le.returnPressed.connect(self.loadCommand) self.tree = TreeView() self.table = QTableView() self.name = '' self.data = None self.lay.addWidget(self.tree) menu = self.menuBar().addMenu('Options') self.isTable = menu.addAction('Table') self.isTable.setCheckable(True) self.isTable.setShortcut('Alt+T') self.isTable.changed.connect(self.reloadModel) def clearModels(self): self.tree.setModel(None) self.table.setModel(None) def reloadModel(self): table = self.isTable.isChecked() if table: table = (isinstance(self.data, list) and all( isinstance(obj, dict) for obj in self.data)) or (isinstance(self.data, dict) and all( isinstance(obj, list) for obj in self.data.values())) self.clearModels() if table: self.table.setModel(ObjTable(self.data)) self.table.resizeColumnsToContents() self.table.setSortingEnabled(True) self.lay.replaceWidget(self.tree, self.table) else: self.tree.setModel(ObjConverter(self.data, name=self.name)) self.tree.expandAll() self.lay.replaceWidget(self.table, self.tree) self.table.setVisible(table) self.tree.setVisible(not table) def loadCommand(self): text = self.le.text() if os.path.isfile(text): with open(text) as fd: obj = loadJson(fd.read()) else: try: out = subprocess.check_output(text, shell=True).decode('utf-8') except subprocess.CalledProcessError as e: obj = str(e) else: try: obj = loadJson(out) except ValueError as e: try: obj = loadJson('[%s]' % ','.join(out.strip().split('\n'))) except ValueError: obj = str(e) self.setData(obj, text) def setFile(self, f): self.le.setText(f) def setData(self, obj, name=''): self.data = obj self.name = name self.reloadModel()
class SectionEditor(QWidget): sectionEditorCopied = pyqtSignal(object) def __init__(self, fullwidth): QWidget.__init__(self) from widgets.hyperlink import HyperLink from widgets.flatbutton import FlatButton from widgets.section import Section from widgets.content import ContentType from widgets.elementeditor import ElementEditor, Mode self.fullwidth = fullwidth self.section = None self.id = None self.cssclass = None self.style = None self.attributes = None self.setAutoFillBackground(True) self.setAcceptDrops(True) self.setBGColor() vbox = QVBoxLayout() vbox.setAlignment(Qt.AlignTop) vbox.setSpacing(5) self.edit_button = FlatButton(":/images/edit_normal.png", ":/images/edit_hover.png") self.copy_button = FlatButton(":/images/copy_normal.png", ":/images/copy_hover.png") self.delete_button = FlatButton(":/images/trash_normal.png", ":/images/trash_hover.png") self.edit_button.setToolTip("Edit Section") self.delete_button.setToolTip("Delete Section") self.copy_button.setToolTip("Copy Section") self.edit_button.setMaximumWidth(24) self.copy_button.setMaximumWidth(24) self.delete_button.setMaximumWidth(24) vbox.addWidget(self.edit_button) vbox.addWidget(self.copy_button) vbox.addWidget(self.delete_button) vboxRight = QVBoxLayout() vboxRight.setAlignment(Qt.AlignLeft) layout = QHBoxLayout() self.layout = QVBoxLayout() layout.addLayout(vbox) addRow = HyperLink("(+) Add Row") vboxRight.addLayout(self.layout) if self.fullwidth: ee = ElementEditor() ee.elementEnabled.connect(self.addElement) ee.elementDragged.connect(self.addElement) # connect(ee, SIGNAL(elementCopied(ElementEditor*)), self, SLOT(copyElement(ElementEditor*))) self.layout.addWidget(ee, 0, Qt.AlignTop) else: vboxRight.addWidget(addRow) layout.addLayout(vboxRight) self.setLayout(layout) self.delete_button.clicked.connect(self.delete) self.copy_button.clicked.connect(self.copy) addRow.clicked.connect(self.addRow) self.edit_button.clicked.connect(self.edit) def edit(self): ce = self.getContentEditor() if ce: ce.sectionEdit(self) def addRow(self): row = Row() self.section._items.append(row) re = RowEditor() re.load(row) self.addRowEditor(re) ce = self.getContentEditor() if ce: ce.editChanged("Add Row") def addRowEditor(self, re): re.rowEditorCopied.connect(self.copyRowEditor) self.layout.addWidget(re) def copyRowEditor(self, re): ren = RowEditor() row = re.row.clone() ren.load(row) self.section._items.append(row) self.addRowEditor(ren) ce = self.getContentEditor() if ce: ce.editChanged("Copy Row") def copy(self): self.sectionEditorCopied.emit(self) def delete(self): pe = self.parentWidget() if pe: pe.removeSection(self) def setBGColor(self): pal = self.palette() if self.fullwidth: pal.setColor(QPalette.Background, QColor("#800080")) else: pal.setColor(QPalette.Background, QColor(self.palette().base().color().name())) self.setPalette(pal) def addElement(self): ee = ElementEditor() self.layout.addWidget(ee, 0, Qt.AlignTop) ee.elementEnabled.connect(self.addElement) ee.elementDragged.connect(self.addElement) # connect(ee, SIGNAL(elementCopied(ElementEditor*)), self, SLOT(copyElement(ElementEditor*))) def addElementEditor(self, ee): ee.elementEnabled.connect(self.addElement) ee.elementDragged.connect(self.addElement) # connect(ee, SIGNAL(elementCopied(ElementEditor*)), self, SLOT(copyElement(ElementEditor*))) self.layout.insertWidget(self.layout.count() - 1, ee, 0, Qt.AlignTop) def setSection(self, section): self.section = section def removeRowEditor(self, re): re.setVisible(False) self.layout.removeWidget(re) def load(self, section): from widgets.elementeditor import ElementEditor, Mode from widgets.roweditor import RowEditor self.section = section for item in self.section.items: if isinstance(item, Row): re = RowEditor() re.load(item) self.addRowEditor(re) else: ee = ElementEditor() ee.setContent(item) ee.setMode(Mode.ENABLED) self.addElementEditor(ee) def getContentEditor(self): pe = self.parentWidget() if pe: sa = pe.parentWidget() if sa: vp = sa.parentWidget() if vp: cee = vp.parentWidget() if cee: return cee return None def dragEnterEvent(self, event): myData = event.mimeData() if myData: if not self.section.fullwidth and isinstance( myData.getData(), RowEditor): # insert a dropzone at the end self.layout.addWidget(DropZone(myData.width, myData.height)) event.accept() elif self.section.fullwidth and isinstance(myData.getData(), ElementEditor): for i in range(self.layout.count()): editor = self.layout.itemAt(i).widget() if editor and editor.mode == Mode.EMPTY: editor.setMode(Mode.DROPZONE) break event.accept() else: event.ignore() else: event.ignore() def dragLeaveEvent(self, event): # remove dropzones for i in range(self.layout.count()): dz = self.layout.itemAt(i).widget() if isinstance(dz, DropZone): dz.hide() self.layout.removeWidget(dz) del dz break editor = self.layout.itemAt(i).widget() if isinstance(editor, ElementEditor) and editor.mode == Mode.DROPZONE: # put editor to the end of the list editor.setMode(Mode.EMPTY) self.layout.removeWidget(editor) self.layout.addWidget(editor) break event.accept() def dragMoveEvent(self, event): myData = event.mimeData() if myData: re = myData.getData() if isinstance(re, RowEditor): height = 0 row = 0 # evaluate position for the dropzone to be placed for i in range(self.layout.count()): editor = self.layout.itemAt(i).widget() if isinstance(editor, RowEditor): if event.pos().y() > height and event.pos().y( ) < height + editor.height(): break height += editor.height() row = row + 1 # find dropzone and replace it to location for i in range(self.layout.count()): dz = self.layout.itemAt(i).widget() if isinstance(dz, DropZone): if i != row: self.layout.insertWidget(row, dz) break event.setDropAction(Qt.MoveAction) event.accept() else: ee = myData.getData() if ee: row = event.pos().y() / 50 for i in range(self.layout.count()): editor = self.layout.itemAt(i).widget() if editor and editor.mode == Mode.DROPZONE: if i != row: # put dropzone under mouse pointer self.layout.insertWidget(row, editor) break event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() else: event.ignore() def dropEvent(self, event): myData = event.mimeData() if myData: re = myData.getData() if isinstance(re, RowEditor): # place the dragged RowEditor to the place where DropZone is now for i in range(self.layout.count()): dz = self.layout.itemAt(i).widget() if isinstance(dz, DropZone): dz.hide() self.layout.replaceWidget(dz, re) new_pos = i re.show() del dz break ce = self.getContentEditor() if ce: myData.source_list.remove(re.row) self.section.insertElement(re.row, new_pos) ce.editChanged("Move Row") event.setDropAction(Qt.MoveAction) event.accept() else: ee = myData.getData() if isinstance(ee, ElementEditor): for i in range(self.layout.count()): dz = self.layout.itemAt(i).widget() if isinstance( dz, ElementEditor) and dz.mode == Mode.DROPZONE: # remove widget if it belongs to self layout self.layout.removeWidget(ee) # replace dropzone with dragged element self.layout.replaceWidget(dz, ee) new_pos = i # and put dropzone to the end of the list dz.setMode(Mode.EMPTY) self.layout.removeWidget(dz) self.layout.addWidget(dz) break ee.dropped() ee.show() ee.elementEnabled.disconnect() ee.elementDragged.disconnect() # ee.elementCopied.disconnect() ee.elementEnabled.connect(self.addElement) ee.elementDragged.connect(self.addElement) # ee.elementCopied.connect(self.copyElement) ce = self.getContentEditor() if ce: myData.source_list.remove(ee.content) self.section.insertElement(ee.content, new_pos) ce.editChanged("Move Element") event.setDropAction(Qt.MoveAction) event.accept() else: event.ignore() else: event.ignore() def enableColumnAcceptDrop(self, mode): for i in range(self.layout.count()): re = self.layout.itemAt(i).widget() if isinstance(re, RowEditor): re.enableColumnAcceptDrop(mode) def mousePressEvent(self, event): mimeData = WidgetMimeData() mimeData.setSize(self.size().width(), self.size().height()) mimeData.setData(self) pixmap = QPixmap(self.size()) self.render(pixmap) drag = QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(event.pos()) drag.setPixmap(pixmap) pe = self.parentWidget() pe.removeSectionEditor(self) pe.enableColumnAcceptDrop(False) pe.enableSectionAcceptDrop(False) self.hide() if drag.exec(Qt.MoveAction) == Qt.IgnoreAction: pe.addSection(self) self.show() pe.enableColumnAcceptDrop(True) pe.enableSectionAcceptDrop(True) def removeElement(self, content): self.section._items.remove(content)
class SkillsetsOverTime(QWidget): def __init__(self, stats: backend.XmlStats, link_group: LinkGroup): super().__init__() self._stats = stats self._acc_rating_over_time: Optional[Any] = None # Will be calculated on-demand self._link_group = link_group self._layout = QVBoxLayout() self.setLayout(self._layout) self._plot = QWidget() # This dummy will be replaced by setup function later self._layout.addWidget(self._plot) bottom_pane = QWidget() sub_layout = QHBoxLayout() bottom_pane.setLayout(sub_layout) self._layout.addWidget(bottom_pane) self._cursor_pos_span = QLabel() self._cursor_pos_span.setWordWrap(True) sub_layout.addWidget(self._cursor_pos_span) sub_layout.addWidget(vertical_separator()) display_options = QComboBox() display_options.addItem("Show all scores") display_options.addItem("Show AAA-/AAAA-only") display_options.currentIndexChanged.connect(self._current_index_changed) sub_layout.addWidget(display_options) self._current_index_changed(0) # Trigger first render def _current_index_changed(self, index: int): if index == 0: new_plot = self._setup_skillsets() elif index == 1: new_plot = self._setup_acc_rating() else: print(f"Warning: unknown dropdown index {index}. Ignoring") return self._layout.replaceWidget(self._plot, new_plot) self._plot = new_plot self._layout.invalidate() # Causes glitches otherwise def _crosshair_moved_skillsets(self, cursor_x: datetime) -> None: rating = find_rating_at(cursor_x, self._stats.skillsets_over_time) or [0, 0, 0, 0, 0, 0, 0, 0] text = f"{cursor_x.date()}: " for i in range(8): color = globals.SKILLSET_COLORS_8[i] name = globals.SKILLSET_NAMES_8[i] text_color = globals.SKILLSET_CONTRASTING_TEXT_COLORS_8[i] text += f'<span style="background-color:#{color}; color:#{text_color}">{name}: <b>{rating[i]:.2f}</b> </span>' self._cursor_pos_span.setText(text) def _setup_skillsets(self) -> PlotWrapper: plot_items = [] for i in range(8): plot_items.append(PlotItem( data=LinePlotItem(points=[(dt, rating[i]) for dt, rating in self._stats.skillsets_over_time]), color=globals.SKILLSET_COLORS_8[i], legend_name=globals.SKILLSET_NAMES_8[i], )) # Make overall line thick plot_items[0].data.width *= 3 # type: ignore return PlotWrapper( item=plot_items, title="Skillsets over time", datetime_x_axis=True, show_x_crosshair=True, crosshair_move_callback=self._crosshair_moved_skillsets, link_group=self._link_group, ) def _crosshair_moved_acc(self, cursor_x: datetime) -> None: if not self._acc_rating_over_time: print("Warning: acc_rating_over_time not set in mouse move handler; skipping") return normal_rating = find_rating_at(cursor_x, self._acc_rating_over_time.normal) or 0.0 aaa_rating = find_rating_at(cursor_x, self._acc_rating_over_time.aaa) or 0.0 aaaa_rating = find_rating_at(cursor_x, self._acc_rating_over_time.aaaa) or 0.0 text = f"{cursor_x.date()}: " +\ f'<span style="background-color:#{ALL_GRADES_COLOR}; color:#000000">All: <b>{normal_rating:.2f}</b> </span>' +\ f'<span style="background-color:#{globals.AAA_COLOR}; color:#000000">AAA: <b>{aaa_rating:.2f}</b> </span>' +\ f'<span style="background-color:#{globals.AAAA_COLOR}; color:#000000">AAAA: <b>{aaaa_rating:.2f}</b> </span>' self._cursor_pos_span.setText(text) def _setup_acc_rating(self) -> PlotWrapper: if not self._acc_rating_over_time: self._acc_rating_over_time = blocking_loading_bar( lambda *args: backend.calculate_acc_rating_over_time(self._stats, *args), "Calculating accuracy ratings", ) def make_plot_item(ratings: List[Tuple[date, float]], color: str, name: str) -> PlotItem: return PlotItem( data=LinePlotItem( points=ratings, width=3, # we have 3 distinct lines, might as well make them thicc ), color=color, legend_name=name, ) return PlotWrapper( item=[ make_plot_item(self._acc_rating_over_time.normal, ALL_GRADES_COLOR, "All scores"), make_plot_item(self._acc_rating_over_time.aaa, globals.AAA_COLOR, "Only AAA"), make_plot_item(self._acc_rating_over_time.aaaa, globals.AAAA_COLOR, "Only AAAA"), ], title="Skillsets over time", datetime_x_axis=True, show_x_crosshair=True, crosshair_move_callback=self._crosshair_moved_acc, link_group=self._link_group, )
class Display(QWidget): def __init__(self, parent=None): super(Display, self).__init__(parent) self.setWindowTitle("Perudo Online") # We have to keep a reference to `Client` as it is a QThread self.client = Client() self.client.connection_made.connect(self.update_connection_status) self.client.name_allowed.connect(self.confirm_name_allowed) self.client.lobby_joined.connect(self.populate_lobby_layout) self.client.lobby_update_info.connect(self.update_lobby_layout) self.menu_layout = self.create_menu_layout() self.name_layout = self.create_enter_name_layout() #self.game_layout = self.create_other_player_layout("North") stacked_layout = QStackedLayout(self) stacked_layout.addWidget(self.menu_layout) stacked_layout.addWidget(self.name_layout) #stacked_layout.addWidget(self.lobby_layout) #stacked_layout.addWidget(self.game_layout) self.setLayout(stacked_layout) self.client.start() def create_menu_layout(self): menu_layout = QVBoxLayout() self.connection_status = QLabel("No Connection") menu_layout.addWidget(self.connection_status) self.start_button = QPushButton("New Game") menu_layout.addWidget(self.start_button) quit_button = QPushButton("Quit") menu_layout.addWidget(quit_button) self.start_button.setEnabled(False) self.start_button.clicked.connect(self.start_game) quit_button.clicked.connect(self.quit) frame = QFrame() frame.setLayout(menu_layout) return frame def create_enter_name_layout(self): layout = QVBoxLayout() text = QLabel("Enter your name:") layout.addWidget(text) self.name_input = QLineEdit() layout.addWidget(self.name_input) self.name_enter_button = QPushButton("Enter") layout.addWidget(self.name_enter_button) self.name_allowed_label = QLabel() layout.addWidget(self.name_allowed_label) self.name_enter_button.clicked.connect(self.enter_name) frame = QFrame() frame.setLayout(layout) return frame def create_lobby_layout(self): print("Creating lobby layout") # Name lobby id and time left on left, all players on right layout = QHBoxLayout() # Left left_layout = QVBoxLayout() name_label = QLabel("-") left_layout.addWidget(name_label) self.lobby_id_label = QLabel("-") left_layout.addWidget(self.lobby_id_label) self.time_left = QLabel("Time Left: -") left_layout.addWidget(self.time_left) layout.addLayout(left_layout) # Right right_frame = QFrame() self.names_list_layout = QVBoxLayout() self.name_labels = [] for i in range(MAX_PLAYERS): label = QLabel("[placeholder]") self.name_labels.append(label) self.names_list_layout.addWidget(label) right_frame.setLayout(self.names_list_layout) layout.addWidget(right_frame) frame = QFrame() frame.setLayout(layout) return frame def populate_lobby_layout(self, lobby_id, initial_names): # Called once when the initial lobby data is sent from the server self.lobby_id_label.setText(lobby_id) def update_lobby_layout(self, time_left, name_list): # Called each time an update is received from the server print(f"Updating lobby layout {time_left}, {name_list}") ##self.time_left_id.setText(f"Time Left: {time_left}") new_name_labels = [] for i in range(len(self.name_labels)): label = QLabel(name_list[i]) new_name_labels.append(label) self.names_list_layout.replaceWidget(self.name_labels[i], new_name_labels[i]) self.name_labels = new_name_labels def create_play_layout(self, player_names): play_layout = QGridLayout def create_other_player_layout(self, name): # Creates a dice mat, a cup, a name label and the place to write what # bids the player made layout = QVBoxLayout() player_name = QLabel(name) scroll = QScrollArea() scroll.setMaximumHeight(90) scroll.setWidgetResizable(True) # CRITICAL inner = QFrame(scroll) inner.setLayout(QVBoxLayout()) scroll.setWidget(inner) # CRITICAL for i in range(50): inner.layout().addWidget(QLabel(f"{i} threes")) layout.addWidget(player_name) layout.addWidget(scroll) frame = QFrame() frame.setLayout(layout) return frame def enter_name(self): print(f"Starting game with name {self.name_input.text()}") self.name_enter_button.setDisabled(True) self.client.set_nickname(self.name_input.text()) def confirm_name_allowed(self, name_valid): if name_valid: self.lobby_layout = self.create_lobby_layout() self.layout().addWidget(self.lobby_layout) self.layout().setCurrentIndex(2) self.name_allowed_label.setText("") else: self.name_allowed_label.setText("Name already taken") self.name_enter_button.setEnabled(True) def start_game(self): self.layout().setCurrentIndex(1) def set_up(self): print("Creating window...") print("[Enter name here:]") print("[Start Game] (Disabled)") print("[Quit]") def quit(self): print("Closing window...") QApplication.quit() def update_connection_status(self, status): self.connected = status if self.connected: print("We have a connection, can click on [Start Game] now") self.connection_status.setText("Connected") self.start_button.setEnabled(True) else: print("We have lost connection") self.connection_status.setText("No Connection") self.start_button.setEnabled(False) def get_menu_input(self): # Return whether any buttons have been pressed rand = random() if rand > 0.99: print("Clicked on 'start'") return "start" #elif rand < 0.01: # print("Clicked on 'quit'") # return "quit" else: return None def get_name(self): # Returns what was in the entry box #name = choice(["Oin", "Gloin", "Gimli", "Thorin", "Ori", # "Nori", "Dori", "Fili", "Kili", "Bifur", "Bofur", # "Bombur", "Balin", "Dwalin"]) name = choice(["Oin", "Gloin", "Ori"]) return name def load_lobby(self): print("Displaying lobby...") print("No lobby joined yet") def ask_for_new_name(self): print("You need to input a different name") def get_new_name(self): # Merge with get_name()? name = choice([ "Oin", "Gloin", "Gimli", "Thorin", "Ori", "Nori", "Dori", "Fili", "Kili", "Bifur", "Bofur", "Bombur", "Balin", "Dwalin" ]) return name def join_lobby(self, init_names): print("Joined lobby with players {} already in".format(init_names)) def update_lobby(self, time_left, player_name_list, starting_soon): print("{} seconds left".format(time_left)) print("{} players in lobby".format(player_name_list)) if starting_soon: print("Starting game soon") def load_game(self, player_name_list): print("Loading game screen with player {}".format(player_name_list)) def start_round(self, dice_list, dice_quantities): print("Resetting round: \nYour dice: {}\nOther dice:".format( dice_list, dice_quantities))
class VariantInfoWidget(QWidget): """Creates a simple about dialog. The about dialog contains general information about the application and shows the copyright notice. That's why the class has no attributes or return values. """ legendChanged = pyqtSignal() def __init__(self): super().__init__() self.setMinimumWidth(220) self._OXYGEN_PATH_22 = os.path.join("resources", "icons", "oxygen", "22") self.model = None self.curves = [] self.results = QWidget() # main layout self.layout = QVBoxLayout(self) #self.layout.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.results) self.showResults() def setModel(self, model): self.model = model self.model.dataChanged.connect(self.update) #self.model.modelReset.connect(self.update) self.model.modelReset.connect(self.clear) # das muss optimiert werden, weil dies private Signale sind # es dient dazu, dass gelöschte, oder veränderte (verschobene) Zeilen # nicht mehr ausgewählt werden können (selectionModel) #self.model.rowsRemoved.connect(self.clear) #self.model.rowsMoved.connect(self.clear) #self.model.calculated.connect(self.calculate) def clear(self): self.curves.clear() self.showResults() def updateResults(self, index): self.curves.append(index) def updateColor(self, index, color): self.model.setData(index, color.name(), TreeModel.ColorRole) self.legendChanged.emit() def showResults(self): new = QWidget() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) # title label of the results area self.titleLabel = QLabel("<b>" + QApplication.translate("VariantInfoWidget", "Legend and result(s)") + ":</b>") layout.addWidget(self.titleLabel) if self.curves: # headline description = QLabel(QApplication.translate("VariantInfoWidget", "Break even line for")) layout.addSpacing(10) layout.addWidget(description) # show legend for all plotted curves for curve in self.curves: layout.addSpacing(6) vertical = QHBoxLayout() vertical.setContentsMargins(0, 0, 0, 0) line = ColorLine(curve) line.farbeDef = curve.data(TreeModel.ColorRole) line.colorChanged.connect(self.updateColor) vertical.addWidget(line) vertical.addSpacing(10) vertical.addWidget(QLabel( curve.parent().data(TreeModel.IdentificationRole) + " " + QApplication.translate("VariantInfoWidget", "and") + " " + curve.data(TreeModel.IdentificationRole))) layout.addLayout(vertical) result = QHBoxLayout() result.setContentsMargins(0, 0, 0, 0) result.addSpacing(35) # check, if the plant count is smaller than the calculation point = curve.data(TreeModel.ResultRole) * self.model.projectData("length") resultText = QApplication.translate("VariantInfoWidget", "The costs are equal") if self.model.projectData("count") < point: resultText = QApplication.translate("VariantInfoWidget", "Tree shelter is profitable") elif self.model.projectData("count") > point: resultText = QApplication.translate("VariantInfoWidget", "Fence is profitable") result.addWidget(QLabel("<i>" + resultText + "</i>")) layout.addLayout(result) # show the color hint layout.addSpacing(10) layout.addWidget(QLabel("(" + QApplication.translate("VariantInfoWidget", "to change the color click on the symbol") + ")", wordWrap=True)) layout.addSpacing(10) helpSymbol = QLabel(pixmap=QPixmap(os.path.join(self._OXYGEN_PATH_22, "system-help.png"))) helpText = ClickableLabel("<a href='#'>" + QApplication.translate("VariantInfoWidget", "Explanation of calculation") + "</a>") helpText.clicked.connect(self.showHelp) helpLayout = QHBoxLayout() helpLayout.setContentsMargins(0, 0, 0, 0) helpLayout.setSpacing(8) helpLayout.addWidget(helpSymbol, alignment=Qt.AlignVCenter) helpLayout.addWidget(helpText, alignment=Qt.AlignVCenter) helpLayout.addStretch() layout.addLayout(helpLayout) # add hints separator = QFrame(frameShadow=QFrame.Sunken, frameShape=QFrame.HLine) # not the best solution but it works # this is very tricky! hintTitle = QLabel("<b>" + QApplication.translate("VariantInfoWidget", "Relevant information:") + "</b>") hintArrow = QLabel("<ul style='list-style-type: square; margin-left: -25px;'>" + "<li>" + QApplication.translate("VariantInfoWidget", "the orange arrow displays the result of the calculation") + "</li></ul>", wordWrap=True) # orangener Pfeil zeigt das Ergebnis der Kalkulation hintLines = QLabel("<ul style='list-style-type: square; margin-left: -25px;'>" + "<li>" + QApplication.translate("VariantInfoWidget", "the auxiliary lines for fence length and number of plants are moveable") + "</li></ul>", wordWrap=True) # Hilfslinien für Zaunlänge und Pflanzenzahl sind beweglich layout.addSpacing(30) layout.addWidget(separator) layout.addWidget(hintTitle) layout.addSpacing(10) layout.addWidget(hintArrow) layout.addSpacing(6) layout.addWidget(hintLines) layout.addStretch() else: # no curve was plotted # there is no result available layout.addSpacing(10) layout.addWidget(QLabel(QApplication.translate("VariantInfoWidget", "No results available!"))) layout.addStretch() new.setLayout(layout) self.layout.replaceWidget(self.results, new) self.results.deleteLater() self.results = new def showHelp(self): # create the documentation path with # the current locale settings docFile = os.path.join("doc", "documentation_" + self.locale().name()[:2] + ".pdf") # on every platfrom a different # start operation is needed if sys.platform == "win32": os.startfile(docFile) elif sys.platform == "darwin": subprocess.call(("open", docFile)) elif sys.platform.startswith("linux"): subprocess.call(("xdg-open", docFile))
class InternalsPanel(Panel, QAttribute, qattributes={Toolbox: False}): """A Panel displaying system internals. May be of interest during development. Attributes ---------- _modules: dict A mapping from module names to module information. This can be the acutal module (if already loaded), or a string describing the state of the module ("not loaddd" or "not found"). This information is initialized and updated by the method :py:meth:_updateModules. _moduleName: str = None Graphical elements ------------------ _grid: QGridLayout _moduleGrid: QGridLayout = None """ def __init__(self, **kwargs) -> None: super().__init__(**kwargs) self._modules = {} self._moduleName = None self.initUI() def initUI(self): self._layout = QVBoxLayout() self._grid = QGridLayout() self._grid.addWidget(self.modulesInfo(), 0, 0) self._grid.addLayout(self.systemInfo(), 0, 1) self._layout.addLayout(self._grid) self._info = QLabel("Info") self._layout.addWidget(self._info) self._processInfo = QProcessInfo() self.addAttributePropagation(Toolbox, self._processInfo) self._layout.addWidget(self._processInfo) self.setLayout(self._layout) #@QtCore.pyqtSlot() @protect def _onInfo(self, checked: bool = False): sender = self.sender() print(sender, type(sender), sender.text()) resource = Resource[sender.ID] self.showInfo(ModuleInfo(resource=resource)) #@QtCore.pyqtSlot() @protect def _onUpdateModules(self, checked: bool = False) -> None: self._updateModules() def showInfo(self, info: QWidget): """Show a new info widget. Arguments --------- info: QWidget The widget to be displayed in the info region of the panel. This will replace the previously displayed info widget. """ if self._layout.replaceWidget(self._info, info) is not None: self._info.deleteLater() self._info = info def modulesInfo(self) -> QGroupBox: """Create a QGridLayout with two columns displaying module information. The first column contains the module name, the second column version (if loaded) or availability. Modules are listed in the order given by :py:meth:modules. Returns ------ box: QGroupBox A QWidget displaying the module information. """ box = QGroupBox('Modules') box.setMinimumWidth(300) self._moduleGrid = QGridLayout() self._moduleGrid.addWidget(QLabel("<b>Package</b>", self), 0, 0) self._moduleGrid.addWidget(QLabel("<b>Version</b>", self), 0, 1) for i, m in enumerate(ModuleResource): button = QPushButton(m.label, self) button.ID = m._id # FIXME[hack] button.setFlat(True) button.clicked.connect(self._onInfo) self._moduleGrid.addWidget(button, 1 + i, 0) self._moduleGrid.addWidget(QLabel('', self), 1 + i, 1) self._updateModules() boxLayout = QVBoxLayout() boxLayout.addLayout(self._moduleGrid) updateButton = QPushButton("Update") updateButton.clicked.connect(self._onUpdateModules) boxLayout.addWidget(updateButton) boxLayout.addStretch() box.setLayout(boxLayout) return box def _updateModules(self): """Update the module list. """ for i, m in enumerate(ModuleResource): if m.prepared: info = m.version elif m.available: info = "not loaded" else: info = "not found" self._moduleGrid.itemAtPosition(1 + i, 1).widget().setText(info) def systemInfo(self): pythonBox = QGroupBox('Python') boxLayout = QVBoxLayout() boxLayout.addWidget(QLabel(f"Python version: {sys.version}")) boxLayout.addWidget(QLabel(f"Platform: {sys.platform}")) boxLayout.addWidget(QLabel(f"Prefix: {sys.prefix}")) boxLayout.addWidget(QLabel(f"Executable: {sys.executable}")) boxLayout.addStretch() pythonBox.setLayout(boxLayout) hardwareBox = QGroupBox('Hardware') boxLayout = QVBoxLayout() for i, cpu in enumerate(cpus): prefix = f"{i+1}. " if len(cpus) > 1 else "" boxLayout.addWidget(QLabel(f"{prefix}CPU: {cpu.name}")) for i, gpu in enumerate(gpus): prefix = f"{i+1}. " if len(gpus) > 1 else "" boxLayout.addWidget(QLabel(f"{prefix}GPU: {gpu.name}")) # Memory (1) import os mem_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') # SC_PAGE_SIZE is often 4096. # SC_PAGESIZE and SC_PAGE_SIZE are equal. mem = mem_bytes >> 20 boxLayout.addWidget( QLabel("Total physical memory: {:,} MiB".format(mem))) boxLayout.addStretch() hardwareBox.setLayout(boxLayout) # # Platform # systemBox = QGroupBox('System') boxLayout = QVBoxLayout() import platform boxLayout.addWidget(QLabel(f"node: {platform.node()}")) # boxLayout.addWidget(QLabel(f"uname: {platform.uname()}")) boxLayout.addWidget(QLabel(f"system: {platform.system()}")) boxLayout.addWidget(QLabel(f"release: {platform.release()}")) # boxLayout.addWidget(QLabel(f"version: {platform.version()}")) boxLayout.addWidget( QLabel(f"machine/processor: " f"{platform.machine()}/" f"{platform.processor()}")) boxLayout.addStretch() systemBox.setLayout(boxLayout) resourcesBox = QGroupBox('Resources') boxLayout = QVBoxLayout() # Memory (2) # a useful solution that works for various operating systems, # including Linux, Windows 7, etc.: try: import psutil mem = psutil.virtual_memory() # mem.total: total physical memory available boxLayout.addWidget( QLabel("Total physical memory: " f"{mem.total}")) process = psutil.Process(os.getpid()) boxLayout.addWidget( QLabel("Memory usage: " f"{process.memory_info().rss}")) except ModuleNotFoundError: pass # For Unixes (Linux, Mac OS X, Solaris) you could also use the # getrusage() function from the standard library module # resource. The resulting object has the attribute ru_maxrss, # which gives peak memory usage for the calling process. # resource is a standard library module. import resource # The Python docs aren't clear on what the units are exactly, # but the Mac OS X man page for getrusage(2) describes the # units as bytes. The Linux man page isn't clear, but it seems # to be equivalent to the information from /proc/self/status, # which is in kilobytes. rusage = resource.getrusage(resource.RUSAGE_SELF) boxLayout.addWidget( QLabel("Peak Memory usage: {:,} kiB".format(rusage.ru_maxrss))) if cuda is not None: button = QPushButton("CUDA") #button.setFlat(True) @protect def slot(clicked: bool): self.showInfo(self.cudaInfo()) button.clicked.connect(slot) boxLayout.addWidget(button) resourcesBox.setLayout(boxLayout) # # layout the boxes # layout = QVBoxLayout() row = QHBoxLayout() row.addWidget(hardwareBox) row.addWidget(pythonBox) row.addWidget(systemBox) layout.addLayout(row) layout.addWidget(resourcesBox) layout.addStretch() return layout def cv2Info(self, cv2): layout = QVBoxLayout() info = cv2.getBuildInformation() text = QPlainTextEdit() fixedFont = QFontDatabase.systemFont(QFontDatabase.FixedFont) text.document().setDefaultFont(fixedFont) text.setReadOnly(True) text.setPlainText(info) layout.addWidget(QLabel(f"Version: {cv2.__version__}")) layout.addWidget(QLabel(f"Library: {cv2.__file__}")) layout.addWidget(text) layout.addStretch() return layout def tensorflowInfo(self, tf): layout = QVBoxLayout() label = QLabel("<b>Tensorflow<b>\n" f"Version = {tf.__version__}") layout.addWidget(label) layout.addWidget(QLabel(f"Tensorflow devices:")) # There is an undocumented method called # device_lib.list_local_devices() that enables you to list # the devices available in the local process (As an # undocumented method, this is subject to backwards # incompatible changes.) from tensorflow.python.client import device_lib local_device_protos = device_lib.list_local_devices() for dev in local_device_protos: layout.addWidget(QLabel(f"Device: {dev.name} ({dev.device_type})")) # Note that (at least up to TensorFlow 1.4), calling # device_lib.list_local_devices() will run some initialization # code that, by default, will allocate all of the GPU memory # on all of the devices (GitHub issue). To avoid this, first # create a session with an explicitly small # per_process_gpu_fraction, or allow_growth=True, to prevent # all of the memory being allocated. See this question for # more details # https://stackoverflow.com/questions/38009682/how-to-tell-if-tensorflow-is-using-gpu-acceleration-from-inside-python-shell layout.addStretch() return layout def kerasInfo(self, keras): layout = QVBoxLayout() layout.addWidget(QLabel(f"Backend: {keras.backend.backend()}")) layout.addStretch() return layout def cudaInfo(self): cudaBox = QGroupBox('CUDA') boxLayout = QVBoxLayout() if os.path.exists('/proc/driver/nvidia/version'): with open('/proc/driver/nvidia/version') as f: driver_info = f.read() match = re.search('Kernel Module +([^ ]*)', driver_info) if match: boxLayout.addWidget(QLabel(f"Kernel module: {match.group(1)}")) match = re.search('gcc version +([^ ]*)', driver_info) if match: boxLayout.addWidget(QLabel(f"GCC version: {match.group(1)}")) boxLayout.addWidget( QLabel(f"NVIDIA Kernel driver: " f"{cuda.driver_version}")) boxLayout.addWidget( QLabel(f"CUDA Toolkit version: " f"{cuda.toolkit_version}")) text = QPlainTextEdit() fixedFont = QFontDatabase.systemFont(QFontDatabase.FixedFont) text.document().setDefaultFont(fixedFont) text.setReadOnly(True) text.setPlainText(str(cuda.nvidia_smi)) text.appendPlainText(str(cuda.nvidia_smi_l)) boxLayout.addWidget(text) # Now use the python module pycuda try: import pycuda.autoinit import pycuda.driver as cuda (free, total) = cuda.mem_get_info() boxLayout.addWidget(QLabel("<b>Global GPU Memory</b>")) boxLayout.addWidget(QLabel(f"Total: {total}")) boxLayout.addWidget(QLabel(f"Free: {free}")) boxLayout.addWidget( QLabel("Global memory occupancy: " f"{free*100/total:2.4}% free")) for devicenum in range(cuda.Device.count()): device = cuda.Device(devicenum) attrs = device.get_attributes() # Beyond this point is just pretty printing print("\n===Attributes for device %d" % devicenum) for (key, value) in attrs.items(): print("%s:%s" % (str(key), str(value))) except ImportError as e: print(e, file=sys.stderr) # ImportError: libcurand.so.8.0 # The problem occurs with the current anaconda version # (2017.1, "conda install -c lukepfister pycuda"). # The dynamic library "_driver.cpython-36m-x86_64-linux-gnu.so" # is linked against "libcurand.so.8.0". However, the cudatookit # installed by anaconda is verion 9.0. boxLayout.addWidget( QLabel("Python CUDA module (pycuda) not availabe")) try: nvmlInfo = QNvmlInfo() boxLayout.addWidget(nvmlInfo) add_timer_callback(nvmlInfo.update) except ImportError as e: print(e, file=sys.stderr) boxLayout.addWidget( QLabel("Python NVML module (py3nvml) not availabe")) cudaBox.setLayout(boxLayout) return cudaBox
class MainUi(QtWidgets.QMainWindow, Ui_MainWindow): # 这里的第一个变量是你该窗口的类型,第二个是该窗口对象。 # 这里是主窗口类型。所以设置成当QtWidgets.QMainWindow。 # 你的窗口是一个会话框时你需要设置成:QtWidgets.QDialog def __init__(self): QtWidgets.QMainWindow.__init__(self) Ui_MainWindow.__init__(self) self.setupUi(self) self.initFrame() def initFrame(self): self.layout = QVBoxLayout(self.frame) self.layout.setContentsMargins(0, 0, 0, 0) # index = self.comboBox.currentIndex() self.pic = MyMplCanvas(self.frame, index=0, loc='0,0', width=80, height=4, dpi=100) self.layout.addWidget(self.pic) def show_instruction(self): self.textBrowser.show() # self.textBrowser.setText( # """可视化AP数据库使用说明: # 1.选择指定数据库 # 2.选择要使用的功能 # """) def open_ap_list(self): file_name, file_type = QtWidgets.QFileDialog.getOpenFileName( self, "请选择SQLite文件", path, "DataBase (*.db)") # 设置文件扩展名过滤,用;间隔 # 注意用双分号间隔 if len(file_name) == 0: return file_name = file_name.replace('/', "\\") # windows下需要进行文件分隔符转换 connection = sq.connect(file_name) cursor = connection.cursor() select = cursor.execute('select Name, Mac from main.ap_table_id ') for row in select: ap_list.append(row[0]) mac_list.append(row[1]) if len(ap_list) > 0: QtWidgets.QMessageBox.information( self, # 使用infomation信息框 "说明", "加载成功", QtWidgets.QMessageBox.Ok) self.tableWidgetAp.setHorizontalHeaderLabels(['Name', 'Mac']) # 设置表格表头数据 self.tableWidgetAp.setColumnCount(4) # 设置表格的列数 self.tableWidgetAp.setRowCount(len(ap_list) / 2 + 1) # 设置表格的行数 self.tableWidgetAp.horizontalHeader().setSectionResizeMode( QtWidgets.QHeaderView.ResizeToContents) # 表格设置成大小随内容改变 self.tableWidgetAp.setEditTriggers( QtWidgets.QAbstractItemView.NoEditTriggers) # 表格设置成只读 self.tableWidgetAp.setAlternatingRowColors(True) # 隔行改变颜色 self.tableWidgetAp.clear() # 表格清空,不清空的话会永远残留 for i in range(len(ap_list)): if i % 2 == 0: self.tableWidgetAp.setItem( i / 2, 0, QTableWidgetItem(ap_list[i])) # 设置表格内容为字符串"content" self.tableWidgetAp.setItem( i / 2, 1, QTableWidgetItem(mac_list[i])) # 设置表格内容为字符串"content" else: self.tableWidgetAp.setItem( i / 2, 2, QTableWidgetItem(ap_list[i])) # 设置表格内容为字符串"content" self.tableWidgetAp.setItem( i / 2, 3, QTableWidgetItem(mac_list[i])) # 设置表格内容为字符串"content" self.comboBox.insertItem(i, ap_list[i]) self.textBrowser.hide() def open_database(self): if len(ap_list) < 1: QtWidgets.QMessageBox.information( self, # 使用infomation信息框 "ERROR", "未读取到AP表单", QtWidgets.QMessageBox.Ok) file_name, file_type = QtWidgets.QFileDialog.getOpenFileName( self, "请选择SQLite文件", path, "DataBase (*.db)") # 设置文件扩展名过滤,用;间隔 if len(file_name) == 0: return file_name = file_name.replace('/', "\\") # windows下需要进行文件分隔符转换 connection = sq.connect(file_name) cursor = connection.cursor() select = cursor.execute('select * from main.wifi_table ') lastX = -1 lastY = -1 for row in select: data_list = [] x = row[1] y = row[2] key = '%d,%d' % (x, y) for i in range(3, 3 + len(ap_list)): data_list.append(row[i]) if lastX == x and lastY == y: data_dict[key] += [data_list] elif key in data_dict.keys(): data_dict[key] += [data_list] else: data_dict[key] = [data_list] lastX = x lastY = y if len(data_dict) > 0: QtWidgets.QMessageBox.information( self, # 使用infomation信息框 "说明", "加载成功", QtWidgets.QMessageBox.Ok) COL_PER_PAGE = 10 self.tableWidgetLoc.setColumnCount(COL_PER_PAGE) # 设置表格的列数 self.tableWidgetLoc.setRowCount( int(len(data_dict) / COL_PER_PAGE) + 1) # 设置表格的行数 self.tableWidgetLoc.horizontalHeader().setSectionResizeMode( QtWidgets.QHeaderView.ResizeToContents) # 表格设置成大小随内容改变 self.tableWidgetLoc.setEditTriggers( QtWidgets.QAbstractItemView.NoEditTriggers) # 表格设置成只读 self.tableWidgetLoc.setAlternatingRowColors(True) # 隔行改变颜色 self.tableWidgetLoc.clear() # 表格清空,不清空的话会永远残留 col = 0 row = 0 for key in data_dict.keys(): loc_list = key.split(',') x = int(loc_list[0]) y = int(loc_list[1]) self.tableWidgetLoc.setItem( row, col, QTableWidgetItem("%d,%d" % (x, y))) # 设置表格内容为字符串"content" col += 1 if col / COL_PER_PAGE > 1: col %= COL_PER_PAGE row += 1 def show_time(self): x = self.spinBoxX.text() y = self.spinBoxY.text() loc = '%s,%s' % (x, y) if loc == '0,0': pass elif x != 0 and y != 0 and loc in data_dict.keys(): pass else: QtWidgets.QMessageBox.information( self, # 使用infomation信息框 "ERROR", "不存在的数据", QtWidgets.QMessageBox.Ok) return index = self.comboBox.currentIndex() newPic = UpdateMplCanvas(self.frame, index, loc, width=80, height=4, dpi=100) self.layout.replaceWidget(self.pic, newPic) self.pic = newPic