class MainWindow(QMainWindow): def __init__(self): super().__init__() self.grid_size = GRID_SIZE #adjusting main window self.resize(TILES_WINDOW_WIDTH, TILES_WINDOW_HEIGHT) self.move(0, 0) self.setWindowTitle("Trainer") #initializing tiles self.addTiles(TILE_WIDTH, TILE_HEIGHT) #initializing menubar self.menubar = QMenuBar(self) #adding menu options self.grid_menu = QMenu(self.menubar) self.grid_menu.setTitle("Grid") self.model_menu = QMenu(self.menubar) self.model_menu.setTitle("Model") self.file_menu = QMenu(self.menubar) self.file_menu.setTitle("File") #adding file submenu options exit = QAction(self) exit.setText("Exit") exit.setShortcut('Alt+F4') exit.triggered.connect(self.exit) self.file_menu.addAction(exit) #adding grid submenu options g3 = QAction(self) g3.setText("3 X 3") g3.triggered.connect(self.toGrid3) g3.setShortcut("3") self.grid_menu.addAction(g3) g5 = QAction(self) g5.setText("5 X 5") g5.triggered.connect(self.toGrid5) g5.setShortcut("5") self.grid_menu.addAction(g5) g7 = QAction(self) g7.setText("7 X 7") g7.triggered.connect(self.toGrid7) g7.setShortcut("7") self.grid_menu.addAction(g7) g9 = QAction(self) g9.setText("9 X 9") g9.setShortcut("9") g9.triggered.connect(self.toGrid9) self.grid_menu.addAction(g9) #add model submenus re_train = QAction(self) re_train.setText("Retrain") re_train.setShortcut('Ctrl+R') re_train.triggered.connect(self.retrain) self.model_menu.addAction(re_train) #registering menus to menubar self.menubar.addAction(self.file_menu.menuAction()) self.menubar.addAction(self.model_menu.menuAction()) self.menubar.addAction(self.grid_menu.menuAction()) #registering menubar self.menubar.move(0, 0) self.menubar.setDefaultUp(False) self.setMenuBar(self.menubar) #initializing and registering statusbar self.statusbar = QStatusBar(self) self.setStatusBar(self.statusbar) def retrain(self): print("retrain") # to be implemented def exit(self): QCoreApplication.instance().quit() def toGrid3(self): self.changeGridSize(3) def toGrid5(self): self.changeGridSize(5) def toGrid7(self): self.changeGridSize(7) def toGrid9(self): self.changeGridSize(9) def changeGridSize(self, size): #change grid size to new size self.grid_size = size #redraw frames to get new look self.drawFrames() def addTiles(self, tile_width, tile_height): # initializing and registering centeral widget self.centeral_widget = QWidget(self) self.setCentralWidget(self.centeral_widget) #initialize tiles self.tiles = [] #add tiles according to grid size for i in range(0, self.grid_size): self.tiles.append([]) for j in range(0, self.grid_size): tile = Tile(self.centeral_widget) tile.move(TILES_MARGIN_LEFT * (j + 1) + tile_width * j, TILES_MARGIN_TOP * (i + 1) + tile_height * i) tile.resize(tile_width, tile_height) self.tiles[i].append(tile) def drawFrames(self): #draw images in frames #initial width and height width = TILE_WIDTH height = TILE_HEIGHT if DYNAMIC_WINDOW_SCALING: #if dynamic scalling is available resize tiles # according to current window size window_width = self.centeral_widget.width() window_height = self.centeral_widget.height() (width, height) = reconfig_tile_geometery(window_width, window_height, self.grid_size) #add tile views for images self.addTiles(width, height) #read test image img = cv2.imread("fish.jpg") #resize test image img = cv2.resize(img, (width, height)) #set test image in all tiles for i in range(0, self.grid_size): for j in range(0, self.grid_size): if random.random() < 0.5: self.tiles[i][j].lable = 1 else: self.tiles[i][j].lable = 0 self.tiles[i][j].image = img self.tiles[i][j].drawImage() def resizeEvent(self, event): self.drawFrames()
class DBogUI(object): def __init__(self): self.db_handler = MyDBHandler() self.sqlTranslator = SqlTranslator() self.page_size = 10 self.former_table_data = [] self.current_table_data = [] self.changedTableData = [] self.cell_editable_flg = 0 self.mainWidget = None self.centerLayout = None self.stackedWidget = None self.statusbar = None self.data_page = None self.data_page_layout = None self.menubar = None self.dataPanel = None self.data_panel_layout = None self.sqlTextEdit = None self.table_widget = None self.btn_panel = None self.btn_panel_layout = None self.addLnBtn = None self.rmvLnBtn = None self.queryBtn = None self.editBtn = None self.saveBtn = None self.treePanel = None self.treePanelLayout = None self.tableTree = None self.translate_page = None self.translate_page_layout = None self.translate_up_panel = None self.translate_up_panel_layout = None self.src_sql_text_edit = None self.dest_sql_text_edit = None self.translate_down_panel = None self.translate_down_panel_layout = None self.from_sql_type_combobox = None self.to_sql_type_combobox = None self.translate_btn = None self.swap_btn = None self.clear_btn = None self.login_page = None self.usmLabel = None self.unmTextEdit = None self.pwdLabel = None self.pwdTextEdit = None self.hostLabel = None self.hostTextEdit = None self.dbNameLabel = None self.dbNameTextEdit = None self.cnntDbBtn = None self.load_cfg_btn = None self.error_widgets = [] self.plain_color = None # setup UI def setup_ui(self, MainWindow): # UI MainWindow MainWindow.setObjectName("MainWindow") MainWindow.resize(900, 600) # center widgets self.mainWidget = QWidget(MainWindow) # 设置字体 self.mainWidget.setFont(QFont("Roman times", 11)) self.mainWidget.setObjectName("mainWidget") MainWindow.setCentralWidget(self.mainWidget) self.centerLayout = QVBoxLayout(self.mainWidget) # 设置stacked widget self.stackedWidget = QStackedWidget(self.mainWidget) self.centerLayout.addWidget(self.stackedWidget) # 设置data page self.build_data_page() # layout不同的比例区分大小 self.data_page_layout.setStretchFactor(self.dataPanel, 4) self.data_page_layout.setStretchFactor(self.treePanel, 1) # 设置login面板 self.build_login_page() # 设置translate面板 self.build_translate_page() # 将三个面板,加入stackedWidget self.stackedWidget.addWidget(self.data_page) self.stackedWidget.addWidget(self.login_page) self.stackedWidget.addWidget(self.translate_page) # menu self.build_menu_bar(MainWindow) # status bar self.statusbar = QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) # 刷新 self.re_translate_ui(MainWindow) QMetaObject.connectSlotsByName(MainWindow) # refresh tree list self.db_handler.config(None, None, None, None) self.paint_tree() # data page def build_data_page(self): self.data_page = QWidget(self.mainWidget) self.centerLayout.addWidget(self.data_page) self.data_page_layout = QHBoxLayout(self.data_page) # 设置data面板 self.build_tree_panel() # 设置data面板 self.build_data_panel() # set event self.set_data_page_event() # menu def build_menu_bar(self, MainWindow): self.menubar = QMenuBar(MainWindow) self.menubar.setGeometry(QRect(0, 0, 400, 50)) self.menubar.move(100, 100) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) # 创建一个事件和一个特定图标 show_data_action = QAction(QIcon('../resources/icon/database.png'), 'Operate', self) # show_data_action.setShortcut('Ctrl+Q') # 设置事件的快捷方式 show_data_action.setStatusTip('show data panel') # 设置事件的状态提示 show_data_action.triggered.connect(lambda: self.switch_page(0)) # 事件的触发 login_menu = self.menubar.addMenu('&Data') # 添加菜单file login_menu.addAction(show_data_action) # 菜单添加事件 # 创建一个事件和一个特定图标 show_login_action = QAction(QIcon('../resources/icon/configure.png'), 'Config', self) # show_login_action.setShortcut('Ctrl+P') # 设置事件的快捷方式 show_login_action.setStatusTip('show login panel') # 设置事件的状态提示 show_login_action.triggered.connect(lambda: self.switch_page(1)) # 事件的触发 login_menu = self.menubar.addMenu('&Login') # 添加菜单file login_menu.addAction(show_login_action) # 菜单添加事件 # 创建一个事件和一个特定图标 show_translate_action = QAction(QIcon('../resources/icon/translate.png'), 'Translate', self) # show_login_action.setShortcut('Ctrl+P') # 设置事件的快捷方式 show_translate_action.setStatusTip('show translate page') # 设置事件的状态提示 show_translate_action.triggered.connect(lambda: self.switch_page(2)) # 事件的触发 translate_menu = self.menubar.addMenu('&Translate') # 添加菜单file translate_menu.addAction(show_translate_action) # 菜单添加事件 # 设置data面板 def build_data_panel(self): # data panel self.dataPanel = QWidget(self.data_page) self.data_page_layout.addWidget(self.dataPanel) self.data_panel_layout = QVBoxLayout(self.dataPanel) # SQL输入框 self.sqlTextEdit = QTextEdit(self.dataPanel) self.sqlTextEdit.setObjectName("textEdit") # self.sqlTextEdit.setText("Enter your SQL here...") self.data_panel_layout.addWidget(self.sqlTextEdit) # 数据表格 self.table_widget = TableWidget(self.dataPanel) self.table_widget.init_ui(0, 0, self.dataPanel) self.table_widget.set_page_controller(0) # 表格设置页码控制 self.table_widget.control_signal.connect(self.control_page) self.table_widget.setFixedSize(700, 400) self.data_panel_layout.addWidget(self.table_widget) # build inside panel self.build_btn_panel() self.data_panel_layout.setStretchFactor(self.sqlTextEdit, 2) self.data_panel_layout.setStretchFactor(self.table_widget, 6) self.data_panel_layout.setStretchFactor(self.btn_panel, 2) # button panel def build_btn_panel(self): # button panel self.btn_panel = QWidget(self.data_page) self.btn_panel.setFont(QFont("YaHei", 10)) self.data_panel_layout.addWidget(self.btn_panel) self.btn_panel_layout = QHBoxLayout(self.btn_panel) # 表格操作:增加数据行按钮 self.addLnBtn = QPushButton(self.btn_panel) self.addLnBtn.setMaximumSize(100, 80) self.addLnBtn.setObjectName("addLineButton") self.btn_panel_layout.addWidget(self.addLnBtn) # 表格操作:增加数据行按钮 self.rmvLnBtn = QPushButton(self.btn_panel) self.rmvLnBtn.setObjectName("rmvLineButton") self.btn_panel_layout.addWidget(self.rmvLnBtn) # 查询按钮 self.queryBtn = QPushButton(self.btn_panel) # self.queryBtn.setGeometry(QRect(150, 500, 100, 50)) self.queryBtn.setObjectName("QueryButton") self.btn_panel_layout.addWidget(self.queryBtn) # 更新按钮 self.editBtn = QPushButton(self.btn_panel) # self.editBtn.setGeometry(QRect(150, 500, 100, 50)) self.editBtn.setObjectName("EditButton") self.btn_panel_layout.addWidget(self.editBtn) # 保存按钮 self.saveBtn = QPushButton(self.btn_panel) # self.saveBtn.setGeometry(QRect(225, 500, 100, 50)) self.saveBtn.setObjectName("SaveButton") self.btn_panel_layout.addWidget(self.saveBtn) # set partition / relative size self.btn_panel_layout.setStretchFactor(self.addLnBtn, 1) self.btn_panel_layout.setStretchFactor(self.rmvLnBtn, 1) self.btn_panel_layout.setStretchFactor(self.queryBtn, 1) self.btn_panel_layout.setStretchFactor(self.editBtn, 1) self.btn_panel_layout.setStretchFactor(self.saveBtn, 1) # left catalog tree panel def build_tree_panel(self): self.treePanel = QWidget(self.data_page) self.treePanel.setFont(QFont("SimHei", 11)) self.treePanelLayout = QVBoxLayout(self.treePanel) # self.treePanel.setGeometry(QRect(0, 0, 100, 600)) self.data_page_layout.addWidget(self.treePanel) # tableTree list self.tableTree = QTreeWidget(self.treePanel) self.treePanelLayout.addWidget(self.tableTree) # 设置列数 self.tableTree.setColumnCount(1) self.tableTree.setColumnWidth(0, 100) # 设置头的标题 self.tableTree.setHeaderLabel('Table List') # 绑定点击事件 self.tableTree.clicked.connect(self.on_tree_clicked) # 加载树形菜单 def paint_tree(self): if not CTools.isEmpty(self.db_handler.db_name): self.tableTree.clear() self.sqlTextEdit.setText("use %s;show tables;" % self.db_handler.db_name) table_lst = self.show_tables() # repaint tree nodes root = QTreeWidgetItem(self.tableTree) root.setText(0, self.db_handler.db_name) for i in range(len(table_lst)): table_name = table_lst[i] table_node = QTreeWidgetItem(root) table_node.setText(0, table_name) self.tableTree.addTopLevelItem(root) # data page def build_translate_page(self): self.translate_page = QWidget(self.mainWidget) self.centerLayout.addWidget(self.translate_page) self.translate_page_layout = QVBoxLayout(self.translate_page) self.build_translate_panel() # 设置data面板 def build_translate_panel(self): # translate panel self.translate_up_panel = QWidget(self.translate_page) self.translate_page_layout.addWidget(self.translate_up_panel) # append widget self.translate_up_panel_layout = QHBoxLayout(self.translate_up_panel) # SQL输入框 self.src_sql_text_edit = QTextEdit(self.translate_up_panel) self.src_sql_text_edit.setObjectName("src_sql_text_edit") self.src_sql_text_edit.setText("Enter source SQL to translate here...") self.translate_up_panel_layout.addWidget(self.src_sql_text_edit) # SQL输入框 self.dest_sql_text_edit = QTextEdit(self.translate_up_panel) self.dest_sql_text_edit.setObjectName("dest_sql_text_edit") self.dest_sql_text_edit.setText("SQL translate result will be placed here...") self.dest_sql_text_edit.setReadOnly(True) self.translate_up_panel_layout.addWidget(self.dest_sql_text_edit) # translate panel self.translate_down_panel = QWidget(self.translate_page) self.translate_page_layout.addWidget(self.translate_down_panel) # append widget self.translate_down_panel_layout = QHBoxLayout(self.translate_down_panel) # select from sql type self.from_sql_type_combobox = QComboBox(self.translate_down_panel) self.from_sql_type_combobox.setMaximumSize(150, 120) self.from_sql_type_combobox.setObjectName("from_sql_type_combobox") self.from_sql_type_combobox.addItems(self.sqlTranslator.valid_from_dialect) self.translate_down_panel_layout.addWidget(self.from_sql_type_combobox) self.plain_color = self.from_sql_type_combobox.palette().color(QPalette.Background).toRgb() # select to sql type self.to_sql_type_combobox = QComboBox(self.translate_down_panel) self.to_sql_type_combobox.setMaximumSize(150, 120) self.to_sql_type_combobox.setObjectName("to_sql_type_combobox") # self.to_sql_type_combobox.addItems(['', 'mssql', 'sqlserver', 'mssqlserver', 'mysql', 'oracle', 'db2', 'db2udb']) self.to_sql_type_combobox.addItems(self.sqlTranslator.valid_to_dialect) self.translate_down_panel_layout.addWidget(self.to_sql_type_combobox) # translate按钮 self.translate_btn = QPushButton(self.translate_down_panel) self.translate_btn.setMaximumSize(150, 120) self.translate_btn.setObjectName("Translate") self.translate_btn.setText("Translate") self.translate_down_panel_layout.addWidget(self.translate_btn) self.translate_btn.clicked.connect(self.on_translate) # 交换按钮 self.swap_btn = QPushButton(self.translate_down_panel) self.swap_btn.setMaximumSize(150, 120) self.swap_btn.setObjectName("Swap") self.swap_btn.setText("Swap") self.translate_down_panel_layout.addWidget(self.swap_btn) self.swap_btn.clicked.connect(self.on_swap) # 清空按钮 self.clear_btn = QPushButton(self.translate_down_panel) self.clear_btn.setMaximumSize(150, 120) self.clear_btn.setObjectName("Clear") self.clear_btn.setText("Clear") self.translate_down_panel_layout.addWidget(self.clear_btn) self.clear_btn.clicked.connect(self.on_clear) def on_translate(self): src_sql_str = self.src_sql_text_edit.toPlainText() from_type = self.from_sql_type_combobox.currentText() to_type = self.to_sql_type_combobox.currentText() error_msg = "" if not src_sql_str or src_sql_str == "Enter source SQL to translate here...": error_msg += "source SQL should not be empty\n" self.src_sql_text_edit.setTextBackgroundColor(QColor(255, 0, 0, 255)) self.error_widgets.append(self.src_sql_text_edit) else: if self.src_sql_text_edit in self.error_widgets: self.error_widgets.remove(self.src_sql_text_edit) if not from_type: error_msg += "from SQL Type should not be empty\n" self.from_sql_type_combobox.setStyleSheet("QComboBox{color: rgb(255,0,0,255)}") self.error_widgets.append(self.from_sql_type_combobox) else: if self.from_sql_type_combobox in self.error_widgets: self.error_widgets.remove(self.from_sql_type_combobox) if not to_type: error_msg += "to SQL Type should not be empty\n" self.to_sql_type_combobox.setStyleSheet("QComboBox{color: rgb(255,0,0,255)}") self.error_widgets.append(self.to_sql_type_combobox) else: if self.to_sql_type_combobox in self.error_widgets: self.error_widgets.remove(self.to_sql_type_combobox) if self.error_widgets: QMessageBox.warning(None, "Warning", error_msg) return if self.src_sql_text_edit in self.error_widgets: self.src_sql_text_edit.setTextBackgroundColor(QColor(255, 255, 255, 255)) if self.from_sql_type_combobox in self.error_widgets: self.from_sql_type_combobox.setStyleSheet("QComboBox{color: rgb%s}" % str(self.plain_color.getRgb())) if self.to_sql_type_combobox in self.error_widgets: self.to_sql_type_combobox.setStyleSheet("QComboBox{color: rgb%s}" % str(self.plain_color.getRgb())) dest_sql_str = self.sqlTranslator.web_translate(src_sql_str, from_type, to_type) self.dest_sql_text_edit.setText(dest_sql_str) def on_swap(self): # origin # from_sql_type_index = self.from_sql_type_combobox.currentIndex() # to_sql_type_index = self.to_sql_type_combobox.currentIndex() from_sql_type_text = self.from_sql_type_combobox.currentText() to_sql_type_text = self.to_sql_type_combobox.currentText() src_sql_str = self.src_sql_text_edit.toPlainText() dest_sql_str = self.dest_sql_text_edit.toPlainText() # change content self.from_sql_type_combobox.setCurrentIndex( self.sqlTranslator.get_opposite_sql_type(from_sql_type_text, 'from')) self.to_sql_type_combobox.setCurrentIndex(self.sqlTranslator.get_opposite_sql_type(to_sql_type_text, 'to')) self.dest_sql_text_edit.setText(src_sql_str) self.src_sql_text_edit.setText(dest_sql_str) def on_clear(self): self.from_sql_type_combobox.setCurrentIndex(0) self.to_sql_type_combobox.setCurrentIndex(0) self.dest_sql_text_edit.setText("") self.src_sql_text_edit.setText("") # show data after clicking the menu item in tree def on_tree_clicked(self): item = self.tableTree.currentItem() table_name = item.text(0) # no response when click database label if table_name != self.db_handler.db_name: cTool.logger.info("switch to data of table, name: %s" % table_name) self.sqlTextEdit.setText("select * from %s limit 0, %d;" % (table_name, self.page_size)) self.do_query() # when press append record button def on_append_record(self, table_name, page_size): if self.is_cell_editable(): self.sqlTextEdit.setText("select * from %s limit 0, %d;" % (table_name, page_size)) self.do_query() else: self.warn_action("Table is not allowed to append record now") # when action is fobidden def warn_action(self, err_msg="illegal action"): cTool.logger.info("%s" % err_msg) QMessageBox.warning(None, "Warning", err_msg) # when press remove record button def on_remove_record(self): if self.is_cell_editable(): cell_item_list = self.table_widget.table.selectedItems() count = len(cell_item_list) row_num_set = set() for x in range(0, count): table_item = cell_item_list[x] row_num_set.add(self.table_widget.table.row(table_item)) selected_pk_set = set( self.former_table_data[row_num][self.db_handler.def_pk_index] for row_num in row_num_set) self.db_handler.delete_sql = self.db_handler.buildDeleteSQL(self.db_handler.def_table_name, self.db_handler.def_pk_name, selected_pk_set) # rmv_cnt = self.db_handler.modifyRecords(delete_sql) # print("updated count is %d for SQL %s" % (rmv_cnt, delete_sql)) # self.do_query() self.former_table_data = [former_row_data for former_row_data in self.former_table_data if former_row_data[self.db_handler.def_pk_index] not in selected_pk_set] self.update_table_data(self.former_table_data, self.db_handler.def_field_name_lst, False) else: self.warn_action("Table is not allowed to delete record now") # 设置login面板 def build_login_page(self): # login panel self.login_page = QWidget(self.stackedWidget) self.login_page.setGeometry(QRect(100, 100, 600, 600)) # self.login_page_layout = QVBoxLayout(self.login_page) # username label self.usmLabel = QLabel(self.login_page) self.usmLabel.setGeometry(QRect(100, 100, 150, 50)) self.usmLabel.setText("username ") # self.login_page_layout.addWidget(self.usmLabel) # username input self.unmTextEdit = QLineEdit(self.login_page) self.unmTextEdit.setText("") self.unmTextEdit.setGeometry(QRect(300, 100, 450, 50)) # self.login_page_layout.addWidget(self.unmTextEdit) # password label self.pwdLabel = QLabel(self.login_page) self.pwdLabel.setGeometry(QRect(100, 150, 150, 50)) self.pwdLabel.setText("password ") # self.login_page_layout.addWidget(self.pwdLabel) # password input self.pwdTextEdit = QLineEdit(self.login_page) self.pwdTextEdit.setText("") self.pwdTextEdit.setGeometry(QRect(300, 150, 450, 50)) # self.login_page_layout.addWidget(self.pwdTextEdit) # host label self.hostLabel = QLabel(self.login_page) self.hostLabel.setGeometry(QRect(100, 200, 120, 50)) self.hostLabel.setText("host address ") # self.login_page_layout.addWidget(self.hostLabel) # host input self.hostTextEdit = QLineEdit(self.login_page) self.hostTextEdit.setText("") self.hostTextEdit.setGeometry(QRect(300, 200, 450, 50)) # self.login_page_layout.addWidget(self.hostTextEdit) # database name label self.dbNameLabel = QLabel(self.login_page) self.dbNameLabel.setGeometry(QRect(100, 250, 150, 50)) self.dbNameLabel.setText("database name ") # self.login_page_layout.addWidget(self.dbNameLabel) # database name input self.dbNameTextEdit = QLineEdit(self.login_page) self.dbNameTextEdit.setText("") self.dbNameTextEdit.setGeometry(QRect(300, 250, 450, 50)) # self.login_page_layout.addWidget(self.dbNameTextEdit) # confirm to connect database self.cnntDbBtn = QPushButton(self.login_page) self.cnntDbBtn.setObjectName("DbButton") self.cnntDbBtn.setGeometry(QRect(100, 350, 300, 50)) # self.login_page_layout.addWidget(self.cnntDbBtn) # connect database with config file self.load_cfg_btn = QPushButton(self.login_page) self.load_cfg_btn.setObjectName("LoadConfigButton") self.load_cfg_btn.setGeometry(QRect(450, 350, 300, 50)) # self.login_page_layout.addWidget(self.load_cfg_btn) # set event self.set_login_panel() # build login panel def set_login_panel(self): self.cnntDbBtn.clicked.connect(self.cnnt_db) self.load_cfg_btn.clicked.connect(self.re_config_db) # connect to database def cnnt_db(self): unmStr = self.unmTextEdit.text() pwdStr = self.pwdTextEdit.text() hostStr = self.hostTextEdit.text() dbNameStr = self.dbNameTextEdit.text() self.db_handler.config(hostStr, unmStr, pwdStr, dbNameStr) self.paint_tree() self.switch_page(0) # connect to database with configuration file def re_config_db(self): self.db_handler.config(mVars.host, mVars.username, mVars.password, mVars.database_name) # set label text of widget def re_translate_ui(self, MainWindow): _translate = QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "DBog")) self.setWindowIcon(QIcon("../resources/icon/ball.ico")) self.queryBtn.setText(_translate("MainWindow", "Query")) self.editBtn.setText(_translate("MainWindow", "Edit")) self.saveBtn.setText(_translate("MainWindow", "Save")) self.cnntDbBtn.setText(_translate("MainWindow", "ConnectByInputConfiguration")) self.load_cfg_btn.setText(_translate("MainWindow", "LoadConfigurationFile")) self.addLnBtn.setText(_translate("MainWindow", "AppendRecord")) self.rmvLnBtn.setText(_translate("MainWindow", "RemoveRecord")) # set event of data page def set_data_page_event(self): self.queryBtn.clicked.connect(self.do_query) self.editBtn.clicked.connect(self.do_edit) self.saveBtn.clicked.connect(self.do_save) self.addLnBtn.clicked.connect(lambda: self.on_append_record(self.db_handler.def_table_name, self.page_size - 1)) self.rmvLnBtn.clicked.connect(self.on_remove_record) # switch to another page def switch_page(self, pnIndex): self.stackedWidget.setCurrentIndex(int(pnIndex)) # execute query action def do_query(self): cmd_str = self.sqlTextEdit.toPlainText().replace(";", "") # 获取数据 result_set = self.db_handler.get_all_result(cmd_str) # 获取表结构定义 # db_filed_lst = self.db_handler.gen_alter(self.db_handler.def_table_name) # self.db_handler.field_name_lst = [db_filed["Field"] for db_filed in db_filed_lst] self.db_handler.gen_filed_name_list() # withdraw former table data / cast value None to empty string self.former_table_data = [[str(item) if item else "" for item in row] for row in result_set] # change button status to enable or not self.change_btn_status() # fill in table with empty line self.refresh_table(cmd_str) cTool.logger.info("result set for %s is %s" % ( cmd_str, ','.join([str(row_data) for row_data in result_set]))) # change button status to enable or not def change_btn_status(self): if self.is_cell_editable(): self.addLnBtn.setEnabled(True) self.rmvLnBtn.setEnabled(True) self.saveBtn.setEnabled(True) else: self.addLnBtn.setEnabled(False) self.rmvLnBtn.setEnabled(False) self.saveBtn.setEnabled(False) # refresh table widget def refresh_table(self, cmd_str): row_cnt = len(self.former_table_data) if row_cnt > 0: col_cnt = len(self.former_table_data[0]) while row_cnt < self.page_size: self.former_table_data.append(["" for i in range(col_cnt)]) row_cnt = row_cnt + 1 # count record page_cnt = self.count_record(cmd_str) # refresh table self.update_table_data(self.former_table_data, self.db_handler.def_field_name_lst, True) # refresh table page self.refresh_table_pager(page_cnt) # execute count of record def count_record(self, cmd_str): if "limit" in cmd_str: cmd_str = cmd_str.split("limit")[0] cnt_sql = "select count(1) from (%s) sub" % cmd_str ret_cnt = self.db_handler.get_single_result(cnt_sql) page_cnt = 0 if ret_cnt and len(ret_cnt) > 0: ret_cnt = int(ret_cnt[0]) page_cnt = int(ret_cnt / 10) if page_cnt % 10 != 0: page_cnt = page_cnt + 1 return page_cnt # make new name of each field def rename_fields(self): ret_dict = self.count_list(self.db_handler.def_field_name_lst) for field_name in self.db_handler.def_field_name_lst: if ret_dict[field_name] > 1: field_name = "%s_%d" % (field_name, ret_dict[field_name]) ret_dict[field_name] = ret_dict[field_name] - 1 # statistic item count in a list def count_list(self, target_lst): ret_dict = {} for i in set(target_lst): ret_dict[i] = target_lst.count(i) return ret_dict # show table of current database def show_tables(self): tables_sql = "show tables;" self.sqlTextEdit.setText(tables_sql) return [tbl_name_tp[0] for tbl_name_tp in self.db_handler.get_all_result(tables_sql)] # execute update def do_edit(self): cmd_str = self.sqlTextEdit.toPlainText() row_count = self.db_handler.modifyRecords(cmd_str) info_msg = "Edit finish, effected row count: %d" % row_count cTool.logger.info(info_msg) QMessageBox.information(self, "Info", info_msg) # @decorator() # execute save action def do_save(self): # edit result set of multi tables is forbidden if self.is_cell_editable(): # clear first self.current_table_data.clear() row_count = self.table_widget.table.rowCount() column_count = self.table_widget.table.columnCount() for i in range(0, row_count): curRowData = [] for j in range(0, column_count): cellValStr = self.table_widget.table.item(i, j).text() curRowData.append(cellValStr) self.current_table_data.append(curRowData) # assemble SQL from data deleteSQL = self.db_handler.delete_sql if deleteSQL: # reset to empty string self.db_handler.delete_sql = "" else: dataLst = self.get_delete_data() deleteSQL = self.db_handler.buildDeleteSQL(self.db_handler.def_table_name, self.db_handler.def_pk_name, dataLst) if dataLst else "" cTool.logger.info(deleteSQL) dataLst = self.get_insert_data() insertSQL = self.db_handler.buildInsertSQL(self.db_handler.def_table_name, dataLst) if dataLst else "" cTool.logger.info(insertSQL) rmCnt = self.db_handler.modifyRecords(deleteSQL) if deleteSQL else 0 inCnt = self.db_handler.modifyRecords(insertSQL) if insertSQL else 0 info_msg = "Save finish, effect record count removed: %d,inserted: %d" % (rmCnt, inCnt) cTool.logger.info(info_msg) QMessageBox.information(self, "Info", info_msg) else: self.warn_action("Table is not allowed to update now") # is table cell item editable def is_cell_editable(self): self.cell_editable_flg = QtCore.Qt.ItemIsEnabled if self.db_handler.is_combine_sql else QtCore.Qt.ItemIsEditable return self.cell_editable_flg == 2 # withdraw delete data def get_delete_data(self): fmrSet = set(map(lambda x: ",".join(x), self.former_table_data)) curSet = set(map(lambda x: ",".join(x), self.current_table_data)) diffSet = fmrSet.difference(curSet) return list(map(lambda diffStr: diffStr.split(",")[self.db_handler.def_pk_index], diffSet)) # withdraw insert data def get_insert_data(self): curSet = set(map(lambda x: ",".join(x), self.current_table_data)) fmrSet = set(map(lambda x: ",".join(x), self.former_table_data)) diffSet = curSet.difference(fmrSet) return list(map(lambda diffStr: diffStr.split(","), diffSet)) # update/refresh table data def update_table_data(self, matrix_data, fd_name_list, update_header_flg): row_cnt = len(matrix_data) col_cnt = len(matrix_data[0]) if len(matrix_data) > 0 and len(matrix_data[0]) > 0 else 0 # refresh table model struct self.clear_table_data() # if update_header_flg: self.refresh_table_header(fd_name_list, row_cnt, col_cnt) # refresh table data for row_num in range(0, row_cnt): for col_num in range(0, col_cnt): cell_data = str(matrix_data[row_num][col_num]) if matrix_data[row_num][col_num] else "" # 设置表格内容(行, 列) 文字 self.table_widget.table.setItem(row_num, col_num, QTableWidgetItem(cell_data)) # update/refresh table header def refresh_table_header(self, fd_name_list, row_cnt, col_cnt): self.table_widget.table.setRowCount(row_cnt) self.table_widget.table.setColumnCount(col_cnt) self.table_widget.table.setHorizontalHeaderLabels(fd_name_list) # update/refresh table pager def refresh_table_pager(self, page_count): self.table_widget.totalPageNum.setText(str(page_count)) # clear table data def clear_table_data(self): self.table_widget.table.setRowCount(0) self.table_widget.table.setColumnCount(0) # config table item def touch_table_item(self): flag = QtCore.Qt.ItemIsEnabled if self.db_handler.is_combine_sql else QtCore.Qt.ItemIsEditable col_cnt = self.table_widget.table.colorCount() row_cnt = self.table_widget.table.rowCount() for col_num in range(0, col_cnt): for row_num in range(0, row_cnt): QTableWidgetItem(self.table_widget.table.item(row_cnt, col_cnt)).setFlags(flag) # 设置第二列不可编辑 # self.table_widget.table.setItemDelegateForColumn(col_num, EmptyDelegate(self)) # self.table_widget.table.setItemDelegateForColumn(col_num, QTableWidget.itemDelegate()) # control page def control_page(self, signal): total_page = self.table_widget.show_total_page() if "home" == signal[0]: self.table_widget.curPage.setText("1") elif "pre" == signal[0]: if 1 == int(signal[1]): QMessageBox.information(self, "提示", "已经是第一页了", QMessageBox.Yes) return self.table_widget.curPage.setText(str(int(signal[1]) - 1)) elif "next" == signal[0]: if total_page == int(signal[1]): QMessageBox.information(self, "提示", "已经是最后一页了", QMessageBox.Yes) return self.table_widget.curPage.setText(str(int(signal[1]) + 1)) elif "final" == signal[0]: self.table_widget.curPage.setText(str(total_page)) elif "confirm" == signal[0]: if total_page < int(signal[1]) or int(signal[1]) < 0: QMessageBox.information(self, "提示", "跳转页码超出范围", QMessageBox.Yes) return self.table_widget.curPage.setText(signal[1]) self.change_table_content() # 改变表格内容 # change table pager and content def change_table_content(self): """根据当前页改变表格的内容""" cur_page = int(self.table_widget.curPage.text()) # 每页默认十条数据 cTool.logger.info("current page: %s" % cur_page) page_limit_sql = "limit %s, %s" % ((cur_page - 1) * 10, 10) query_sql = "select * from %s %s;" % (self.db_handler.def_table_name, page_limit_sql) self.sqlTextEdit.setText(query_sql) self.do_query()
class MainWindow(QMainWindow): def __init__(self): super().__init__() #adjusting main window self.resize(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT) self.move(0, 0) #setting scaling factor = 1 self.zoom = 1 #initializing and registering centeral widget self.centeral_widget = QWidget(self) self.setCentralWidget(self.centeral_widget) #initializing frame view self.frame_panel = DLabel(self.centeral_widget, self) # position frame panel self.frame_panel.move(FRAME_MARGIN_LEFT, FRAME_MARGIN_TOP) # set initial image self.frame_panel.setPixmap(QPixmap("initial.png")) #fur testing self.frame_panel.content = cv2.imread("initial.png") # enabling custom context menu self.setContextMenuPolicy(Qt.CustomContextMenu) #initializing menubar self.menubar = QMenuBar(self) #adding menu options self.file_menu = QMenu(self.menubar) self.zoom_menu = QMenu(self.menubar) self.marker_menu = QMenu(self.menubar) self.bounding_boxes = QMenu(self.menubar) #registering menubar self.menubar.move(0, 0) self.menubar.setDefaultUp(False) self.setMenuBar(self.menubar) #initializing and registering statusbar self.statusbar = QStatusBar(self) self.setStatusBar(self.statusbar) #add permanent frame lable to statusbar self.statusbar.frame_lable = QLabel(self) self.statusbar.frame_lable.setText("") self.statusbar.frame_lable.resize(100, 50) self.statusbar.frame_lable.move(DEFAULT_WINDOW_WIDTH - 100, DEFAULT_WINDOW_HEIGHT - 37) # set initail status tip self.statusbar.setStatusTip("Please choose a video file to begin") self.initialize_submenus() #assign visual texts to window, menus and submenus self.setTexts() #initailize video path self.vid_path = "" self.vid = False #adding slider for quick seek self.slider = QSlider(self.centeral_widget) #setting slider geometery self.slider.resize(DEFAULT_WINDOW_WIDTH - SLIDER_MARGINS * 2, SLIDER_HEIGHT) self.slider.move( SLIDER_MARGINS, DEFAULT_WINDOW_HEIGHT - STATUSBAR_HEIGHT - SLIDER_HEIGHT - SLIDER_MARGINS) #setting orientation self.slider.setOrientation(Qt.Horizontal) #connecting mouse event self.slider.valueChanged.connect(self.moveSliderToClickedPosition) self.slider.setDisabled(True) # initialize context menu self.initContextMenu() # initializing mongo client and db self.database_client = MongoClient() self.db = self.database_client.fish # initializing collection self.collection = False def initContextMenu(self): # initialize custom context menu and submenu self.context_menu = QMenu(self) self.context_sub_menu = QMenu('Class', self) # create a delete action self.delete_action = QAction('Delete', self) self.delete_action.triggered.connect(self.frame_panel.deleteMarker) # create get lable action self.ask_lable = QAction('Ask Lable', self) self.ask_lable.triggered.connect(self.frame_panel.getLable) # adding dictionary for reverse search self.classes = {} # initializing class group self.class_group = QActionGroup(self) # adding submenu actions for item in CONFIGURED_CLASSES: self.classes[item] = QAction(item, self) self.classes[item].setCheckable(True) self.class_group.addAction(self.classes[item]) # connecting group to handlers and setting default class self.class_group.triggered.connect(self.frame_panel.toggleMarkerClass) self.classes[CONFIGURED_CLASSES[0]].setChecked(True) # add delete action to menu self.context_menu.addAction(self.delete_action) # add ask lable action to menu self.context_menu.addAction(self.ask_lable) # add class actions to submenu self.context_sub_menu.addActions(self.class_group.actions()) # regester submenu to menu self.context_menu.addMenu(self.context_sub_menu) def initialize_submenus(self): #intializing open submenu self.open_submenu = QAction(self) self.open_submenu.setShortcut('Ctrl+F') self.open_submenu.setStatusTip("Open") self.open_submenu.triggered.connect(self.selectFile) # intializing export submenu self.export_submenu = QAction(self) self.export_submenu.setShortcut('Ctrl+E') self.export_submenu.setStatusTip("Export") self.export_submenu.triggered.connect(self.exportImages) self.export_submenu.setDisabled(True) # intializing export submenu self.init_submenu = QAction(self) self.init_submenu.setShortcut('Ctrl+I') self.init_submenu.setStatusTip("Initialize") self.init_submenu.triggered.connect(self.initializeWithAlgorithm) self.init_submenu.setDisabled(True) #initializing options for zoom menu self.p50_submenu = QAction(self) self.p50_submenu.setStatusTip("50%") self.p50_submenu.setCheckable(True) self.p50_submenu.val = 0.5 self.p100_submenu = QAction(self) self.p100_submenu.setStatusTip("100%") self.p100_submenu.setCheckable(True) self.p100_submenu.val = 1.0 self.p150_submenu = QAction(self) self.p150_submenu.setStatusTip("150%") self.p150_submenu.setCheckable(True) self.p150_submenu.val = 1.5 self.p200_submenu = QAction(self) self.p200_submenu.setStatusTip("200%") self.p200_submenu.setCheckable(True) self.p200_submenu.val = 2.0 self.zoom_group = QActionGroup(self) self.zoom_group.addAction(self.p50_submenu) self.zoom_group.addAction(self.p100_submenu) self.zoom_group.addAction(self.p150_submenu) self.zoom_group.addAction(self.p200_submenu) self.p100_submenu.setChecked(True) self.zoom_group.setDisabled(True) self.zoom_group.triggered.connect(self.changeZoom) #registering file submenus self.file_menu.addAction(self.open_submenu) # registering bounding box submenus self.bounding_boxes.addAction(self.export_submenu) self.bounding_boxes.addAction(self.init_submenu) #registering zoom submenus self.zoom_menu.addActions(self.zoom_group.actions()) #registering menus to menubar self.menubar.addAction(self.file_menu.menuAction()) self.menubar.addAction(self.zoom_menu.menuAction()) self.menubar.addAction(self.bounding_boxes.menuAction()) def setTexts(self): self.setWindowTitle("FIBVID Analyser") #file menu self.file_menu.setTitle("File") self.open_submenu.setText("Open") self.bounding_boxes.setTitle("Boxes") # bouding boxes menu self.export_submenu.setText("Export as Images") self.init_submenu.setText("Initialize with Model") #zoom menu self.zoom_menu.setTitle("Zoom") self.p50_submenu.setText("50%") self.p100_submenu.setText("100%") self.p100_submenu.setText("100%") self.p150_submenu.setText("150%") self.p200_submenu.setText("200%") def selectFile(self): # get the file browser pop-up path, _ = QFileDialog.getOpenFileName(self.statusbar, 'Select Video File', '/home') self.vid_path = path self.initVideo() def exportImages(self): cursor_pos = self.vid.get(cv2.CAP_PROP_POS_FRAMES) markers = self.collection.find({}) markers.batch_size(1000000000) markers = [marker for marker in markers] height, width = self.current_frame.shape[0:2] empty = np.zeros((height, width, 3), np.uint8) center = (int(width / 2), int(height / 2)) i = 0 last = 0 for marker in markers: progress = int(i * 100 / len(markers)) img = empty.copy() cv2.circle(img, center, 100, (255, 255, 255)) cv2.circle(img, center, progress, (255, 255, 255), -1) print(progress) self.setFrame(img) cv2.waitKey(1) last = progress box = [marker["start_pos"], marker["end_pos"]] rbox = RBox.fromPointBoundingBox(box) self.vid.set(cv2.CAP_PROP_POS_FRAMES, marker["frame_no"] - 1) rtt, frame = self.vid.read() patch = rbox.extractPatchFromImage(frame, square=True) name = str(marker["_id"]) name = "./exports/" + name + ".png" cv2.imwrite(name, patch) i += 1 self.initVideo() def showProgress(self, progress, fps): height, width = self.current_frame.shape[0:2] empty = np.zeros((height, width, 3), np.uint8) center = (int(width / 2), int(height / 2)) cv2.circle(empty, center, progress, (255, 255, 255), -1) empty[center[1] - 100:center[1] + 100, center[0] - 100:center[0] + 100] = cv2.bitwise_and(empty[center[1] - 100:center[1] + 100, center[0] - 100:center[0] + 100], empty[center[1] - 100:center[1] + 100, center[0] - 100:center[0] + 100], mask=self.coin) cv2.circle(empty, center, 98, (255, 255, 255)) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(empty, "FPS: {}".format(fps), (10, 20), font, 0.5, (255, 255, 255), 1, cv2.LINE_AA) self.setFrame(empty) def initializeWithAlgorithm(self): self.initVideo() self.analyser = RuntimeABGSC(vid_path=self.vid_path) # read progress image coin = cv2.imread("fish_coin_inv.png") self.coin = np.uint8( cv2.cvtColor(coin, cv2.COLOR_RGB2GRAY) > 150) * 255 # empty collection self.collection.delete_many({}) # frame cout frame_count = self.vid.get(cv2.CAP_PROP_FRAME_COUNT) counter = 0 # disable scroll bar self.slider.setDisabled(True) # disable video self.vid = False markers = [] while (self.analyser.status): # while video is not complete start = time() self.analyser.process(show_output=False) end = time() # increment counter counter += 1 # calculate fps fps = int(1 / (end - start)) # show progress in display window progress = int(counter * 100 / frame_count) self.showProgress(progress, fps) for box in self.analyser.final_boxes: start_pos = (int(box[0][0]), int(box[0][1])) end_pos = (int(box[1][0]), int(box[1][1])) # add resultant marker to markers of current frame marker = Marker(start_pos, end_pos, counter, CONFIGURED_CLASSES[3]) markers.append(marker.toDictionary()) #self.frame_panel.markers.append(marker) # add markers to database self.collection.insert_many(markers) self.initVideo() def changeZoom(self): # get selected option's value zoom = self.zoom_group.checkedAction().val # reset frame according to new scaling self.resetFrame(zoom) def resetFrame(self, zoom): self.zoom = zoom self.frame_panel.zoom = zoom #resize frame panel self.frame_panel.resize(self.vid_height * zoom, self.vid_width * zoom) #resize window if dynamic scaling is enabled if DYNAMIC_WINDOW_SCALING: self.resize( self.vid_height * zoom + FRAME_MARGIN_LEFT + FRAME_MARGIN_RIGHT, self.vid_width * zoom + FRAME_MARGIN_TOP + FRAME_MARGIN_BOTTOM) # reposition slider self.slider.move( SLIDER_MARGINS, self.vid_width * zoom - (SLIDER_HEIGHT + SLIDER_MARGINS)) # resize slider self.slider.resize(self.width() - SLIDER_MARGINS * 2, SLIDER_HEIGHT) # reposition frame lable self.statusbar.frame_lable.move(self.width() - 100, self.height() - 37) self.currentFrame() def initVideo(self): # reset zoom self.zoom = 1.0 self.vid = cv2.VideoCapture() # load selected video rtt = self.vid.open(self.vid_path) # clear slider self.slider.disconnect() # seek slider to start self.slider.setValue(0) self.slider.valueChanged.connect(self.moveSliderToClickedPosition) if rtt == False: if self.vid_path == "": self.statusbar.setStatusTip("No file selected") else: self.statusbar.setStatusTip("Error: Format not supported") # disalbe zoom options self.zoom_group.setDisabled(True) # clean video from memory self.vid = False # disable slider self.slider.setDisabled(True) return else: self.statusbar.setStatusTip("Ready") # set collection self.collection = self.db[self.vid_path] # seek to start self.vid.set(cv2.CAP_PROP_POS_FRAMES, 0) # read first frame rtt, frame = self.vid.read() # extract height and width of video self.vid_width, self.vid_height, self.vid_depth = np.shape(frame) self.vid_width *= self.zoom self.vid_height *= self.zoom self.current_frame = frame.copy() # resize frame view according to the video's geometery self.frame_panel.resize(self.vid_height, self.vid_width) # getting current frame number self.frame_no = self.vid.get(cv2.CAP_PROP_POS_FRAMES) # adding frame no to status tip self.statusbar.frame_lable.setText("Frame: {0}".format( "%05.0i" % int(self.frame_no))) # reset frame to start self.resetFrame(self.zoom) #enable zoom options self.zoom_group.setDisabled(False) #enable slider self.slider.setDisabled(False) # enable algorithmBasedInitialization self.init_submenu.setDisabled(False) self.export_submenu.setDisabled(False) # plot the current frame on canvas self.frame_panel.content = frame.copy() self.setImageFrame(frame) # seek slider to start self.moveSliderToPosition(0) def setImageFrame(self, frame): # load image with markers self.frame_panel.loadMarkers() self.frame_panel.reDraw() self.frame_panel.dragStatus = "Ended" def setFrame(self, frame): # convert raw frame to QPixmap and set it on frame_panel frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) self.frame_panel.setPixmap( QPixmap.fromImage( QImage(frame, self.vid_height * self.zoom, self.vid_width * self.zoom, self.vid_height * self.zoom * self.vid_depth, QImage.Format_RGB888))) def nextFrame(self): # read next frame of video as Image rtt, frame = self.vid.read() if rtt: self.frame_panel.content = frame.copy() self.current_frame = frame.copy() # check if there is a next frame and convert cv Image to Pixmap frame = cv2.resize(frame, None, fx=self.zoom, fy=self.zoom, interpolation=cv2.INTER_CUBIC) # initializing markers on frame_panel self.frame_panel.markers = [] # getting current frame number self.frame_no = self.vid.get(cv2.CAP_PROP_POS_FRAMES) # clear slider self.slider.disconnect() # seek slider to start self.slider.setValue(self.frame_no * 100 / self.vid.get(cv2.CAP_PROP_FRAME_COUNT)) self.slider.valueChanged.connect(self.moveSliderToClickedPosition) self.setImageFrame(frame) #adding frame no to status tip self.statusbar.frame_lable.setText("Frame: {0}".format( "%05.0i" % int(self.frame_no))) def previousFrame(self): # set current frame number to 2 frames backward self.vid.set(cv2.CAP_PROP_POS_FRAMES, self.vid.get(cv2.CAP_PROP_POS_FRAMES) - 2) # get next frame self.nextFrame() def currentFrame(self): self.frame_panel.content = self.current_frame.copy() # check if there is a next frame and convert cv Image to Pixmap frame = cv2.resize(self.current_frame.copy(), None, fx=self.zoom, fy=self.zoom, interpolation=cv2.INTER_CUBIC) self.setImageFrame(frame) def keyPressEvent(self, event): # don't do anything if no video is selected if self.vid == False: return # Key press event on window if type(event) == QKeyEvent and event.key() == Qt.Key_D: # navigate forward if D pressed self.nextFrame() if type(event) == QKeyEvent and event.key() == Qt.Key_A: # navigate backward if A pressed self.previousFrame() if type(event) == QKeyEvent and event.key() == Qt.Key_Plus: # zoom in self.resetFrame(self.zoom + 1) if type(event) == QKeyEvent and event.key() == Qt.Key_Minus: # zoom out if zoom factor is greater than 1 if (self.zoom > 1.0): self.resetFrame(self.zoom - 1) def moveSliderToClickedPosition(self): # enable slider to move with mouse click # get click position relative to slider click_position = self.slider.mapFromGlobal(QCursor.pos()).x() self.moveSliderToPosition(click_position) def moveSliderToPosition(self, position): # set position of slider to position by setting its value slider_completion_ratio = position / self.slider.width() self.slider.setValue(slider_completion_ratio * 100) # seek video accordingly if self.vid: self.vid.set( cv2.CAP_PROP_POS_FRAMES, self.vid.get(cv2.CAP_PROP_FRAME_COUNT) * slider_completion_ratio) # refresh frame self.nextFrame()
class UiMainClientWindow(object): """ Класс, создающий интерфейс главного окна. """ def __init__(self, main_client_window): main_client_window.setObjectName("MainClientWindow") main_client_window.resize(756, 534) main_client_window.setMinimumSize(QSize(756, 534)) self.centralwidget = QWidget(main_client_window) self.centralwidget.setObjectName("centralwidget") self.label_contacts = QLabel(self.centralwidget) self.label_contacts.setGeometry(QRect(10, 0, 101, 16)) self.label_contacts.setObjectName("label_contacts") self.btn_add_contact = QPushButton(self.centralwidget) self.btn_add_contact.setGeometry(QRect(10, 450, 121, 31)) self.btn_add_contact.setObjectName("btn_add_contact") self.btn_remove_contact = QPushButton(self.centralwidget) self.btn_remove_contact.setGeometry(QRect(140, 450, 121, 31)) self.btn_remove_contact.setObjectName("btn_remove_contact") self.label_history = QLabel(self.centralwidget) self.label_history.setGeometry(QRect(300, 0, 391, 21)) self.label_history.setObjectName("label_history") self.text_message = QTextEdit(self.centralwidget) self.text_message.setGeometry(QRect(300, 360, 441, 71)) self.text_message.setObjectName("text_message") self.label_new_message = QLabel(self.centralwidget) self.label_new_message.setGeometry(QRect(300, 270, 450, 76)) self.label_new_message.setObjectName("label_new_message") self.text_menu = QMenuBar(self.label_new_message) self.text_menu.move(0, 51) self.action_bold = QAction(QIcon(os.path.join(STATIC, 'img/b.jpg')), 'Bold', self.text_message) self.action_italic = QAction(QIcon(os.path.join(STATIC, 'img/i.jpg')), 'Italic', self.text_message) self.action_underlined = QAction( QIcon(os.path.join(STATIC, 'img/u.jpg')), 'Underlined', self.text_message) self.action_smile = QAction( QIcon(os.path.join(STATIC, 'img/smile.gif')), 'smile', self.text_message) self.list_contacts = QListView(self.centralwidget) self.list_contacts.setGeometry(QRect(10, 20, 251, 411)) self.list_contacts.setObjectName("list_contacts") self.list_messages = QListView(self.centralwidget) self.list_messages.setGeometry(QRect(300, 20, 441, 271)) self.list_messages.setObjectName("list_messages") self.btn_send = QPushButton(self.centralwidget) self.btn_send.setGeometry(QRect(610, 450, 131, 31)) self.btn_send.setObjectName("btn_send") self.btn_clear = QPushButton(self.centralwidget) self.btn_clear.setGeometry(QRect(460, 450, 131, 31)) self.btn_clear.setObjectName("btn_clear") main_client_window.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(main_client_window) self.menubar.setGeometry(QRect(0, 0, 756, 21)) self.menubar.setObjectName("menubar") self.menu_file = QMenu(self.menubar) self.menu_file.setObjectName("file") self.menu_contacts = QMenu(self.menubar) self.menu_contacts.setObjectName("contacts") self.menu_profile = QMenu(self.menubar) self.menu_profile.setObjectName("profile") main_client_window.setMenuBar(self.menubar) self.statusBar = QStatusBar(main_client_window) self.statusBar.setObjectName("statusBar") main_client_window.setStatusBar(self.statusBar) self.menu_exit = QAction(main_client_window) self.menu_exit.setObjectName("menu_exit") self.menu_add_contact = QAction(main_client_window) self.menu_add_contact.setObjectName("menu_add_contact") self.menu_del_contact = QAction(main_client_window) self.menu_del_contact.setObjectName("menu_del_contact") self.menu_file.addAction(self.menu_exit) self.menu_contacts.addAction(self.menu_add_contact) self.menu_contacts.addAction(self.menu_del_contact) self.menu_contacts.addSeparator() self.menu_profile_avatar = QAction(main_client_window) self.menu_profile_avatar.setObjectName("menu_profile_avatar") self.menu_profile.addAction(self.menu_profile_avatar) self.menu_profile.addSeparator() self.menubar.addAction(self.menu_file.menuAction()) self.menubar.addAction(self.menu_contacts.menuAction()) self.menubar.addAction(self.menu_profile.menuAction()) self.retranslate_ui(main_client_window) self.btn_clear.clicked.connect(self.text_message.clear) QMetaObject.connectSlotsByName(main_client_window) def retranslate_ui(self, main_client_window): _translate = QCoreApplication.translate main_client_window.setWindowTitle( _translate("MainClientWindow", "SPELL Messenger - Client")) self.label_contacts.setText( _translate("MainClientWindow", "Список контактов:")) self.btn_add_contact.setText( _translate("MainClientWindow", "Добавить контакт")) self.btn_remove_contact.setText( _translate("MainClientWindow", "Удалить контакт")) self.label_history.setText( _translate("MainClientWindow", "История сообщений:")) self.label_new_message.setText( _translate("MainClientWindow", "Введите новое сообщение:")) self.btn_send.setText( _translate("MainClientWindow", "Отправить сообщение")) self.btn_clear.setText(_translate("MainClientWindow", "Очистить поле")) self.menu_file.setTitle(_translate("MainClientWindow", "Файл")) self.menu_contacts.setTitle(_translate("MainClientWindow", "Контакты")) self.menu_profile.setTitle(_translate("MainClientWindow", "Профиль")) self.menu_exit.setText(_translate("MainClientWindow", "Выход")) self.menu_profile_avatar.setText( _translate("MainClientWindow", "Аватар")) self.menu_add_contact.setText( _translate("MainClientWindow", "Добавить контакт")) self.menu_del_contact.setText( _translate("MainClientWindow", "Удалить контакт"))