def _aboutToShowTabsMenu(self): self._menuTabs.clear() for idx in range(self.count()): tab = self._weTab(idx) if not tab or tab.isPinned(): continue action = QAction(self) action.setIcon(tab.icon()) if idx == self.currentIndex(): f = action.font() f.setBold(True) action.setFont(f) title = tab.title() title.replace('&', '&&') action.setText(gVar.appTools.truncatedText(title, 40)) # TODO: QVariant::fromValue(qobject_cast<QWidget*>(tab) action.setData(tab) action.triggered.connect(self._actionChangeIndex) self._menuTabs.addAction(action)
class MainWindow(QMainWindow): def __init__(self, app): super(MainWindow, self).__init__() self.app = app print('window created') self.setWindowIcon(QIcon('img/icon.png')) self.setWindowTitle('Kasino') self.setPalette(QPalette(Qt.darkGreen)) self.setup_music() self.statusbar = QStatusBar(self) self.statusbar.setStyleSheet('background: white') self.setStatusBar(self.statusbar) self.statusbar.showMessage('Welcome to the Cassino game!') self.menubar = QMenuBar(self) self.optionsMenu = self.menubar.addMenu('Options') self.music_toggle = QAction() self.music_toggle.setText('Music') self.music_toggle.setShortcut('Ctrl+m') self.music_toggle.setCheckable(True) self.music_toggle.setChecked(True) self.optionsMenu.addAction(self.music_toggle) self.music_toggle.triggered.connect(self.toggle_music) self.speedGroup = QActionGroup(self) self.speedGroup.triggered.connect(self.set_speed) self.slow_speed = QAction('Slow', self.speedGroup) self.slow_speed.setCheckable(True) self.normal_speed = QAction('Normal', self.speedGroup) self.normal_speed.setCheckable(True) self.fast_speed = QAction('Fast', self.speedGroup) self.fast_speed.setCheckable(True) self.vfast_speed = QAction('Very Fast', self.speedGroup) self.vfast_speed.setCheckable(True) self.normal_speed.setChecked(True) self.speed_menu = self.optionsMenu.addMenu('Speed') self.speed_menu.addActions(self.speedGroup.actions()) self.menubar.setMouseTracking(False) self.setMenuBar(self.menubar) self.play_widget = PlayWidget(self) self.main_menu = MainMenu(self) self.start_menu = StartMenu(self) self.widgets = QStackedWidget(self) self.widgets.addWidget(self.play_widget) self.widgets.addWidget(self.main_menu) self.widgets.addWidget(self.start_menu) self.widgets.setCurrentWidget(self.main_menu) self.setCentralWidget(self.widgets) self.setGeometry(25, 50, 1028, 720) self.main_menu.startbutton.clicked.connect(self.init_game) self.main_menu.loadbutton.clicked.connect(self.load_game) self.main_menu.quitbutton.clicked.connect(self.quit) self.play_widget.quit_button.clicked.connect(self.quit_to_menu) self.play_widget.save_button.clicked.connect(self.save_game) self.start_menu.startbutton.clicked.connect(self.start_game) def setup_music(self): self.music = QMediaPlayer() self.playlist = QMediaPlaylist() self.playlist.setPlaybackMode(QMediaPlaylist.Loop) file_name = "sound/bg.mp3" self.media = QMediaContent(QUrl.fromLocalFile(file_name)) self.playlist.addMedia(self.media) self.music.setPlaylist(self.playlist) self.music.setVolume(20) self.music.play() def toggle_music(self): if self.music.isMuted(): self.music.setMuted(False) self.statusbar.showMessage('Music on', 5000) else: self.music.setMuted(True) self.statusbar.showMessage('Music off', 5000) def set_speed(self, action): if action == self.slow_speed: self.play_widget.speed = 1 elif action == self.normal_speed: self.play_widget.speed = 3 elif action == self.fast_speed: self.play_widget.speed = 4 else: self.play_widget.speed = 6 def start_game(self): self.play_widget.init_game( self.start_menu.extract_info_and_init_game()) self.widgets.setCurrentWidget(self.play_widget) self.statusbar.showMessage('Game launched', 2000) def load_game(self): path = QFileDialog.getOpenFileName(self, 'Open save file', QDir.currentPath() + '/sav')[0] if path != '': game, msg, count = load(path) self.play_widget.resume_from_save(game, msg, count) self.widgets.setCurrentWidget(self.play_widget) self.statusbar.showMessage('Loaded save file', 5000) def save_game(self): path = QFileDialog.getSaveFileName(self, 'Create save file', QDir.currentPath() + '/sav')[0] if path != '': save(path, self.play_widget.game, self.play_widget.export_log(), self.play_widget.move_count) self.statusbar.showMessage('Game saved', 5000) def init_game(self): self.widgets.setCurrentWidget(self.start_menu) self.statusbar.showMessage('Starting new game') def quit_to_menu(self): #Reset playwidget self.widgets.removeWidget(self.play_widget) speed = self.play_widget.speed self.play_widget.setParent(None) self.play_widget = PlayWidget(self) self.play_widget.speed = speed self.widgets.addWidget(self.play_widget) self.play_widget.quit_button.clicked.connect(self.quit_to_menu) self.play_widget.save_button.clicked.connect(self.save_game) self.widgets.setCurrentWidget(self.main_menu) def closeEvent(self, *args, **kwargs): #for handling closing from 'x' button self.quit() def quit(self): print('Exited game. Thanks for playing!\n') self.app.exit()
def rebuild_menus(self): fav_menus = cfg.plugin_prefs[cfg.STORE_MENUS] m = self.menu m.clear() in_device_mode = self.gui.location_manager.has_device discovered_plugins = {} for fav_menu in fav_menus: if fav_menu is None: m.addSeparator() continue ac = None paths = list(fav_menu['path']) plugin_name = paths[0] is_device_only_plugin = False if plugin_name == 'Location Manager': # Special case handling since not iaction instances is_device_only_plugin = True paths = paths[1:] for loc_action in self.gui.location_manager.all_actions[1:]: if unicode(loc_action.text()) == paths[0]: if len(paths) > 1: # This is an action on the menu for this plugin or its submenus ac = self._find_action_for_menu( loc_action.menu(), paths[1:], plugin_name) else: # This is a top-level plugin being added to the menu ac = loc_action break else: iaction = self.gui.iactions.get(plugin_name, None) if iaction is not None: if iaction not in discovered_plugins: discovered_plugins[iaction] = True if hasattr(iaction, 'menu'): iaction.menu.aboutToShow.emit() is_device_only_plugin = 'toolbar' in iaction.dont_add_to and 'toolbar-device' not in iaction.dont_add_to if len(paths) > 1: # This is an action on the menu for this plugin or its submenus ac = self._find_action_for_menu( iaction.qaction.menu(), paths[1:], plugin_name) else: # This is a top-level plugin being added to the menu ac = iaction.qaction if ac is None: # We have a menu action that is not available. Perhaps the user # has switched libraries, uninstalled a plugin or for some other # reason that underlying item is not available any more. We still add # a placeholder menu item, but will have no icon and be disabled. mac = QAction(fav_menu['display'], m) mac.setEnabled(False) #print('Favourite Menu: action not found:', fav_menu) else: # We have found the underlying action for this menu item. # Clone the original QAction in order to alias the text for it mac = ActionWrapper(ac, m) mac.setText(fav_menu['display']) if is_device_only_plugin and not in_device_mode: mac.setEnabled(False) m.addAction(mac) m.addSeparator() create_menu_action_unique(self, m, _('&Customize plugin') + '...', 'config.png', shortcut=False, triggered=self.show_configuration)
class Ui(QApplication): def __init__(self): super().__init__(argv) self.w = QMainWindow() self.w.setMinimumWidth(300) self.w.setMinimumHeight(300) # self.w.setWindowTitle(tr("Отправка запросов на ВС АУГО")) self.cw = QScrollArea() # self.__create_ui() self.__showed = False self.__wgts = {} self.cb = QComboBox() self.individuals = [] self.entities = [] self.documents = [] self.doc_files = [] self.__setupUi(self.w) self.w.showMaximized() def report_error(self, msg=None): if not msg: etype, value, tb = exc_info() trace = ''.join(format_exception(etype, value, tb)) delim_len = 40 msg = ("*" * delim_len + "\n%s\n" + "*" * delim_len) % trace error(msg) mb = QMessageBox(QMessageBox.Critical, tr('Ошибка'), str(exc_info()[1])) mb.setDetailedText(msg) mb.exec() def __create_ui(self): self.l = QGridLayout() self.t = QTableWidget(0, 3) self.t.setHorizontalHeaderLabels( ('№ дела (обращения)', 'Дата приёма', 'Дата отправки в СМЭВ')) self.t.resizeColumnsToContents() self.l.addWidget(self.t, 0, 0, 1, 2) w = QWidget() hl = QHBoxLayout(w) hl.setDirection(QHBoxLayout.LeftToRight) hl.addWidget(QWidget()) ok_b = QPushButton(tr('Добавить запрос')) ok_b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum) ok_b.clicked.connect(self.__show_form) hl.addWidget(ok_b) w.setLayout(hl) self.l.addWidget(w, 1, 0, 1, 2) w = QWidget() w.setLayout(self.l) self.cw.setWidget(w) # self.cw.setLayout(self.l) # self.w.setCentralWidget(self.cw) w = QWidget() l = QVBoxLayout() l.addWidget(self.cw) w.setLayout(l) self.w.setCentralWidget(w) def __setupUi(self, mainWindow): mainWindow.setObjectName("MainWindow") self.centralwidget = QWidget(mainWindow) self.centralwidget.setObjectName("centralwidget") self.horizontalLayout = QHBoxLayout(self.centralwidget) self.horizontalLayout.setObjectName("horizontalLayout") self.scrollArea = QScrollArea(self.centralwidget) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollArea") self.scrollAreaWidgetContents = QWidget() self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") self.gridLayout = QGridLayout(self.scrollAreaWidgetContents) self.gridLayout.setObjectName("gridLayout") self.__show_form() self.scrollArea.setWidget(self.scrollAreaWidgetContents) self.horizontalLayout.addWidget(self.scrollArea) mainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(mainWindow) self.menubar.setObjectName("menubar") self.menu = QMenu(self.menubar) self.menu.setObjectName("menu") mainWindow.setMenuBar(self.menubar) self.statusbar = QStatusBar(mainWindow) self.statusbar.setObjectName("statusbar") mainWindow.setStatusBar(self.statusbar) self.action_1 = QAction(mainWindow) self.action_1.setObjectName("action") self.action_1.triggered.connect(self.send) self.action = QAction(mainWindow) self.action.setObjectName("action") self.action.triggered.connect(self.on_action_triggered) self.action_2 = QAction(mainWindow) self.action_2.setObjectName("action_2") self.action_3 = QAction(mainWindow) self.action_3.setObjectName("action_3") self.action_3.triggered.connect(self.get_response) self.menu.addAction(self.action) self.menubar.addAction(self.action_1) self.menubar.addAction(self.action_2) self.menubar.addAction(self.action_3) self.menubar.addAction(self.menu.menuAction()) self.__retranslateUi(mainWindow) QMetaObject.connectSlotsByName(mainWindow) @pyqtSlot(bool) def get_response(self): try: from dmsic import Integration i = Integration(self) res = i.get_response()[0] if res: QMessageBox.information(self.w, tr("Получен ответ"), str(res)) except: self.report_error() @pyqtSlot(bool) def send(self): try: from dmsic import Integration i = Integration(self) declar = {} for k, v in self.__wgts.items(): if k in ('object_address', 'AppliedDocument', 'legal_entity', 'person'): a = {} for key, val in v.items(): if val.metaObject().className() == 'QDateEdit': a[key] = datetime.strptime(val.text(), '%d.%m.%Y') else: a[key] = val.text() declar[k] = a else: if v.metaObject().className() == 'QDateEdit': declar[k] = datetime.strptime(v.text(), '%d.%m.%Y') else: declar[k] = v.text() a = declar[ 'AppliedDocument'] if 'AppliedDocument' in declar else [] for v in self.documents: d = {} for key, val in v.items(): if val.metaObject().className() == 'QDateEdit': d[key] = datetime.strptime(val.text(), '%d.%m.%Y') else: d[key] = val.text() if not self.doc_files: raise Exception('Добавте файл документа') d['file_name'] = self.doc_files[self.documents.index(v)] a.append(d) declar['AppliedDocument'] = a a = declar['person'] if 'person' in declar else [] for v in self.individuals: ind = {} for key, val in v.items(): if key in ('address', 'fact_address'): adr = {} for k, vl in val.items(): adr[k] = vl.text() ind[key] = adr else: if val.metaObject().className() == 'QDateEdit': ind[key] = datetime.strptime( val.text(), '%d.%m.%Y') else: ind[key] = val.text() a.append(ind) declar['person'] = a a = declar['legal_entity'] if 'legal_entity' in declar else [] for v in self.entities: ent = {} for key, val in v.items(): if key == 'address': adr = {} for k, vl in val.items(): adr[k] = vl.text() ent[key] = adr else: if val.metaObject().className() == 'QDateEdit': ent[key] = datetime.strptime( val.text(), '%d.%m.%Y') else: ent[key] = val.text() a.append(ent) declar['legal_entity'] = a i.send(declar) mb = QMessageBox(self.w) mb.information(self.w, tr('Готово'), tr('Запрос отправлен')) except: self.report_error() @pyqtSlot(bool) def on_action_triggered(self): a = Ui_Dialog() d = QDialog() a.setupUi(d) d.exec() def __retranslateUi(self, MainWindow): _translate = QCoreApplication.translate MainWindow.setWindowTitle( _translate("MainWindow", "Отправка запросов на ВС АУГО")) # self.pushButton.setText(_translate("MainWindow", "Добавить")) self.menu.setTitle(_translate("MainWindow", "Справка")) self.action_1.setText(_translate("MainWindow", "Отправить")) self.action_2.setText(_translate("MainWindow", "Настройка")) self.action.setText(_translate("MainWindow", "О программе")) self.action_3.setText(_translate("MainWindow", "Получить ответ")) @pyqtSlot(bool) def __show_form(self): if self.__showed: return self.gridLayout.addWidget( QLabel(tr('№ дела (обращения) <em style="color: red">*</em>'))) w = QLineEdit() self.gridLayout.addWidget(w) w.setFocus() self.__wgts['declar_number'] = w self.gridLayout.addWidget( QLabel( tr('Услуга (код или номер, или наименование)<em style="color: red">*</em>' ))) w = QLineEdit() self.gridLayout.addWidget(w) self.__wgts['service'] = w self.gridLayout.addWidget( QLabel( tr('Дата регистрации запроса <em style="color: red">*</em>'))) de = QDateEdit(QDate().currentDate()) de.setCalendarPopup(True) self.gridLayout.addWidget(de) self.__wgts['register_date'] = de self.gridLayout.addWidget( QLabel( tr('Плановый срок предоставления услуги <em style="color: red">*</em>' ))) de = QDateEdit() self.__wgts['register_date'].dateChanged.connect(de.setMinimumDate) de.setCalendarPopup(True) de.setMinimumDate(self.__wgts['register_date'].date()) self.gridLayout.addWidget(de) self.__wgts['end_date'] = de gb = QGroupBox(tr('Место нахождения объекта услуги')) gb_l = QGridLayout() self.__wgts['object_address'] = self.__add_address(gb_l) gb.setLayout(gb_l) self.gridLayout.addWidget(gb, self.gridLayout.rowCount() + 1, 0, 1, 2) doc = {} gb = QGroupBox(tr('Приложенный документ *')) gb_l = QGridLayout() gb_l.addWidget( QLabel(tr('Наименование документа <em style="color: red">*</em>'))) w = QLineEdit() w.setMaxLength(1024) gb_l.addWidget(w, 0, 1, 1, 1) doc['title'] = w gb_l.addWidget( QLabel(tr('Номер документа <em style="color: red">*</em>'))) w = QLineEdit() w.setMaxLength(50) gb_l.addWidget(w) doc['number'] = w gb_l.addWidget( QLabel(tr('Дата документа <em style="color: red">*</em>'))) w = QDateEdit() w.setCalendarPopup(True) gb_l.addWidget(w) doc['date'] = w gb_l.addWidget( QLabel( tr('Прямая ссылка на файл. Поддерживаются только пртоколы ' 'HTTP, FTP <em style="color: red">*</em>'))) w = QLineEdit() gb_l.addWidget(w) doc['url'] = w gb.setLayout(gb_l) self.gridLayout.addWidget(gb, self.gridLayout.rowCount() + 1, 0, 1, 2) self.documents.append(doc) gb = QGroupBox(tr('Заявители *')) self.dec_layout = QGridLayout() self.cb = QComboBox() self.cb.addItems(('Физическое лицо', 'Юридическое лицо/Индивидуальный предприниматель')) self.dec_layout.addWidget(self.cb) b = QPushButton(tr('Добавить')) b.clicked.connect(self.add_declarant) self.dec_layout.addWidget(b, 0, 1, 1, 1) gb.setLayout(self.dec_layout) self.gridLayout.addWidget(gb, self.gridLayout.rowCount() + 1, 0, 1, 2) b = QPushButton(tr('Добавить файл документа')) b.clicked.connect(self.__add_doc_file) self.gridLayout.addWidget(b) self.file_label = QLabel() self.gridLayout.addWidget(self.file_label) self.warn_label = QLabel(tr("Не удаляйте файл до отправки запроса")) self.warn_label.setStyleSheet('color: red') self.warn_label.setVisible(False) self.gridLayout.addWidget(self.warn_label, self.gridLayout.rowCount() + 1, 0, 1, 2) self.__showed = True @pyqtSlot(bool) def __add_doc_file(self): file_name = QFileDialog.getOpenFileName( caption=tr('Выбурите файл'), filter=tr('Файлы pdf (*.pdf);;Все файлы (*.*)'))[0] self.file_label.setText(file_name) if self.doc_files: self.doc_files = [] self.doc_files.append(file_name) self.warn_label.setVisible(True) def __add_address(self, gb_l): wgts = {} gb_l.addWidget(QLabel(tr('Почтовый индекс'))) w = QLineEdit() gb_l.addWidget(w, 0, 1, 1, 1) wgts['Postal_Code'] = w gb_l.addWidget(QLabel(tr('Регион'))) w = QLineEdit() gb_l.addWidget(w) wgts['Region'] = w gb_l.addWidget(QLabel(tr('Район'))) w = QLineEdit() gb_l.addWidget(w) wgts['District'] = w gb_l.addWidget(QLabel(tr('Муниципальное образование'))) w = QLineEdit() gb_l.addWidget(w) wgts['City'] = w gb_l.addWidget(QLabel(tr('Городской район'))) w = QLineEdit() gb_l.addWidget(w) wgts['Urban_District'] = w gb_l.addWidget(QLabel(tr('Сельсовет'))) w = QLineEdit() gb_l.addWidget(w) wgts['Soviet_Village'] = w gb_l.addWidget( QLabel(tr('Населенный пункт <em style="color: red">*</em>'))) w = QLineEdit() gb_l.addWidget(w) wgts['Locality'] = w cb = QComboBox() cb.addItems(('Вариант 1', 'Вариант 2')) gb_l.addWidget(cb) st = QStackedWidget() p1 = QWidget() l = QGridLayout() l.setSpacing(3) l.addWidget(QLabel(tr('Улица <em style="color: red">*</em>'))) w = QLineEdit() l.addWidget(w, 0, 1, 1, 1) wgts["Street"] = w l.addWidget(QLabel(tr('Дом <em style="color: red">*</em>'))) w = QLineEdit() l.addWidget(w) wgts["House"] = w p1.setLayout(l) st.addWidget(p1) p2 = QWidget() l = QGridLayout() l.setSpacing(3) l.addWidget(QLabel(tr('Ориентир'))) w = QLineEdit() l.addWidget(w, 0, 1, 1, 1) wgts["Reference_point"] = w p2.setLayout(l) st.addWidget(p2) gb_l.addWidget(st, 9, 0, 1, 2) cb.activated.connect(st.setCurrentIndex) gb_l.addWidget(QLabel(tr('Корпус'))) w = QLineEdit() gb_l.addWidget(w) wgts['Housing'] = w gb_l.addWidget(QLabel(tr('Строение'))) w = QLineEdit() gb_l.addWidget(w) wgts['Building'] = w gb_l.addWidget(QLabel(tr('Квартира'))) w = QLineEdit() gb_l.addWidget(w) wgts['Apartment'] = w return wgts @pyqtSlot(bool) def add_declarant(self, var=True, gl=None): if not gl: gl = self.dec_layout dc = {} gb_l = QGridLayout() if self.cb.currentIndex() == 0 or gl != self.dec_layout: # Add Individual gb = QGroupBox(tr('Физическое лицо *')) gb_l.addWidget(QLabel(tr('Фамилия <em style="color: red">*</em>'))) w = QLineEdit() gb_l.addWidget(w, 0, 1, 1, 1) dc['surname'] = w gb_l.addWidget(QLabel(tr('Имя <em style="color: red">*</em>'))) w = QLineEdit() gb_l.addWidget(w) dc['first_name'] = w gb_l.addWidget(QLabel(tr('Отчество'))) w = QLineEdit() gb_l.addWidget(w) dc['patronymic'] = w adr = QGroupBox(tr('Адрес регистрации *')) adr_l = QGridLayout() dc['address'] = self.__add_address(adr_l) adr.setLayout(adr_l) gb_l.addWidget(adr, gb_l.rowCount() + 1, 0, 1, 2) gb.setLayout(gb_l) gl.addWidget(gb, gl.rowCount() + 1, 0, 1, 2) self.individuals.append(dc) else: # Add LegalEntity gb = QGroupBox( tr('Юридическое лицо/Индивидуальный предприниматель *')) gb_l.addWidget( QLabel( tr('Краткое наименование ЮЛ <em style="color: red">*</em>') )) w = QLineEdit() gb_l.addWidget(w, 0, 1, 1, 1) dc['name'] = w adr = QGroupBox(tr('Юридический адрес *')) adr_l = QGridLayout() dc['address'] = self.__add_address(adr_l) adr.setLayout(adr_l) gb_l.addWidget(adr, gb_l.rowCount() + 1, 0, 1, 2) gb.setLayout(gb_l) gl.addWidget(gb, gl.rowCount() + 1, 0, 1, 2) self.entities.append(dc)
class UFDebugToolUI(object): def __init__(self, window=None): self.window = window if window is not None else QWidget super(UFDebugToolUI, self).__init__() self.lang = 'en' self.set_ui() def set_ui(self): self._set_window() self._set_menubar() self._set_tab() def _set_window(self): self.window.setWindowTitle(self.window.tr('UF-Debug-Tool')) self.window.setMinimumHeight(800) self.window.setMinimumWidth(1080) self.main_layout = QVBoxLayout(self.window) def _set_menubar(self): self.menuBar = QMenuBar() self.main_layout.setMenuBar(self.menuBar) fileMenu = self.menuBar.addMenu('File') self.newFileAction = QAction(self.window.tr('New'), self.window) self.newFileAction.setShortcut('Ctrl+N') self.newFileAction.setStatusTip('New File') fileMenu.addAction(self.newFileAction) self.openFileAction = QAction(self.window.tr('Open'), self.window) self.openFileAction.setShortcut('Ctrl+O') self.openFileAction.setToolTip('Open File') fileMenu.addAction(self.openFileAction) self.saveFileAction = QAction(self.window.tr('Save'), self.window) self.saveFileAction.setShortcut('Ctrl+S') self.saveFileAction.setStatusTip('Save File') fileMenu.addAction(self.saveFileAction) self.closeFileAction = QAction(self.window.tr('Close'), self.window) self.closeFileAction.setShortcut('Ctrl+W') self.closeFileAction.setStatusTip('Close File') fileMenu.addAction(self.closeFileAction) self.newFileAction.triggered.connect(self.new_dialog) self.openFileAction.triggered.connect(self.open_dialog) self.saveFileAction.triggered.connect(self.save_dialog) self.closeFileAction.triggered.connect(self.close_dialog) debugMenu = self.menuBar.addMenu('Debug') self.logAction = QAction(self.window.tr('Log'), self.window) self.logAction.setShortcut('Ctrl+D') self.logAction.setStatusTip('Open-Log') self.logAction.triggered.connect(self.control_log_window) debugMenu.addAction(self.logAction) def control_log_window(self): if self.window.log_window.isHidden(): self.window.log_window.show() self.logAction.setText('Close-Log') else: self.window.log_window.hide() self.logAction.setText('Open-Log') def switch_tab(self, index): pass # if index == 2: # self.menuBar.setHidden(False) # else: # self.menuBar.setHidden(True) def _set_tab(self): self.tab_widget = QTabWidget() # self.tab_widget.currentChanged.connect(self.switch_tab) # tab_widget.setMaximumHeight(self.window.geometry().height() // 2) self.main_layout.addWidget(self.tab_widget) toolbox1 = QToolBox() toolbox2 = QToolBox() toolbox3 = QToolBox() toolbox4 = QToolBox() toolbox5 = QToolBox() groupbox1 = QGroupBox() groupbox2 = QGroupBox() groupbox3 = QGroupBox() groupbox4 = QGroupBox() groupbox5 = QGroupBox() toolbox1.addItem(groupbox1, "") toolbox2.addItem(groupbox2, "") toolbox3.addItem(groupbox3, "") toolbox4.addItem(groupbox4, "") toolbox5.addItem(groupbox5, "") self.tab_widget.addTab(toolbox1, "uArm") self.tab_widget.addTab(toolbox2, "xArm") self.tab_widget.addTab(toolbox3, "OpenMV") self.tab_widget.addTab(toolbox4, "Gcode") self.tab_widget.addTab(toolbox5, "WebView") uarm_layout = QVBoxLayout(groupbox1) xarm_layout = QVBoxLayout(groupbox2) openmv_layout = QHBoxLayout(groupbox3) gcode_layout = QVBoxLayout(groupbox4) webview_layout = QVBoxLayout(groupbox5) self.uarm_ui = UArmUI(self, uarm_layout) self.xarm_ui = XArmUI(self, xarm_layout) self.openmv_ui = OpenMV_UI(self, openmv_layout) self.gcode_ui = GcodeUI(self, gcode_layout) self.webview_ui = WebViewUI(self, webview_layout) self.tab_widget.setCurrentIndex(0) def new_dialog(self): self.openmv_ui.textEdit.setText('') self.openmv_ui.textEdit.filename = None self.openmv_ui.label_title.setText('untitled') self.tab_widget.setCurrentIndex(2) self.openmv_ui.textEdit.setDisabled(False) def open_dialog(self): fname = QFileDialog.getOpenFileName(self.window, 'Open file', '') if fname and fname[0]: with open(fname[0], "r") as f: self.openmv_ui.textEdit.setText(f.read()) self.openmv_ui.label_title.setText(fname[0]) self.openmv_ui.textEdit.filename = fname[0] self.tab_widget.setCurrentIndex(2) self.openmv_ui.textEdit.setDisabled(False) def save_dialog(self): widget = self.window.focusWidget() if widget: if not self.openmv_ui.textEdit.filename: fname = QFileDialog.getSaveFileName(self.window, 'Save File', '') if fname and fname[0]: self.openmv_ui.textEdit.filename = fname[0] if self.openmv_ui.textEdit.filename: data = widget.toPlainText() with open(self.openmv_ui.textEdit.filename, "w") as f: f.write(data) def close_dialog(self): self.openmv_ui.textEdit.clear() self.openmv_ui.textEdit.filename = None self.openmv_ui.label_title.setText('') self.openmv_ui.textEdit.setDisabled(True)
class DyTableWidget(QTableWidget): highlightBackground = QColor('#FFD700') def __init__(self, parent=None, readOnly=False, index=True, floatCut=True, autoScroll=True, floatRound=2): """ @index: 是否要插入默认行索引(Org.) @floatRound: 小数点后格式化成几位, 只在@floatCut is True时有效 """ super().__init__(parent) self.setSortingEnabled(True) self.verticalHeader().setVisible(False) if readOnly: self.setEditTriggers(QTableWidget.NoEditTriggers) self.setSelectionBehavior(QAbstractItemView.SelectRows) self._role = Qt.DisplayRole if readOnly else Qt.EditRole self.__index = index # 原始插入的行索引 self._floatCut = floatCut self._floatRoundFormat = '%.{0}f'.format(floatRound) self._autoForegroundCol = None # 指定前景色关键列,如果此列对应的值改变时,将改变所对应行的前景色。包含'Org.'列 self._enableAutoScroll = autoScroll self.setColNames([]) self._initItemMenu() self._initRows() def _initRows(self): self._itemsMap = {} # 由行关键字建立的item的字典, {key: [item]} # mark self._markedItem = None self._markedItemOriginalBackground = None self._markedItemsOriginalForeground = [] # highlight, item is one of item in one row self._highlightedItems = [ ] # [[item, [highlightedItemsOriginalForeground], [highlightedItemsOriginalBackground]]] # find self._findItems = [] self._curFindItemPos = 0 def _clearHighlight(self): # reproduce highlighed items because during cancel highlight procedure element will be deleted from @self._highlightedItems highlightedItems = [item[0] for item in self._highlightedItems] for item in highlightedItems: self._highlight(item) def _clearVisualEffects(self): self._mark(self._markedItem) self._clearHighlight() def __getitem__(self, indices): row, col = indices item = self._getItem(row, col) if item is None: return None return DyCommon.toNumber(item.data(self._role)) def _getItem(self, row, col): # row if isinstance(row, str): item = None if row in self._itemsMap: item = self._itemsMap[row][0] if item is None: return None row = item.row() # column if isinstance(col, int): if self.__index: col += 1 else: col = self._getColPos(col) # get item try: item = self.item(row, col) except: item = None return item def _updateItemsMap(self, rowKey, col, item): if rowKey not in self._itemsMap: self._itemsMap[rowKey] = [] rowLen = len(self._itemsMap[rowKey]) for i in range(rowLen, col + 1): self._itemsMap[rowKey].append(None) self._itemsMap[rowKey][col] = item def _getColPos(self, colName): for i in range(self.columnCount()): item = self.horizontalHeaderItem(i) if colName == item.text(): return i return None def _updateItem(self, row, col, value): """ Update one item, @row and @col can be string or integer. It's gengeral function. @col is included Org. for @col is integer, i.e. it's absolute updating. """ if isinstance(row, str): self._updateItemByRowKey(row, col, value) else: self._updateItemByRowPos(row, col, value) def _updateItemByRowPos(self, row, col, value): if isinstance(col, str): colPos = self._getColPos(col) if colPos is None: # insert a new column with column name colPos = self.columnCount() item = QTableWidgetItem(col) self.setHorizontalHeaderItem(colPos, item) col = colPos # now we take it by positions self._updateItemByPos(row, col, value) def _getColPosWithCreation(self, colName): colPos = self._getColPos(col) if colPos is None: # insert a new column with column name colPos = self.columnCount() item = QTableWidgetItem(col) self.setHorizontalHeaderItem(colPos, item) return colPos def _setAutoRowForeground(self, item): if self._autoForegroundCol is None: return # ignore 'Org.' column if self.__index and item.column() == 0: return # get forground of reference item row = item.row() refItem = self.item(row, self._autoForegroundCol) if not refItem: return # set forground same as reference item item.setForeground(refItem.foreground()) # we still need to go through row if value of reference item changed if item.column() == self._autoForegroundCol: # get foreground for row color = self.getForegroundOverride(item.data(self._role)) if color is None: if item.background() == Qt.white: # for qdarkstyle color = Qt.black else: color = Qt.white # no foreground changed if item.foreground() == color: return for i in range(self.columnCount()): if self.__index and i == 0: continue item = self.item(row, i) if item: item.setForeground(color) def _setItemData(self, item, value): """ 设置Item的值和相应的格式 string值将会保持原始格式 """ assert value is None or isinstance(value, float) or isinstance( value, int) or isinstance(value, str), 'type(value) is {0}'.format( type(value)) # set data if isinstance(value, float): if not np.isnan(value): if self._floatCut: value = self._floatRoundFormat % value else: value = None item.setData(self._role, value) # set auto row color self._setAutoRowForeground(item) if self._enableAutoScroll: self.scrollToItem(item) def _setItemDataFast(self, item, value): """ 快速设置Item的值 string值将会保持原始格式 """ assert value is None or isinstance(value, float) or isinstance( value, int) or isinstance(value, str), 'type(value) is {0}'.format( type(value)) # set data if isinstance(value, float): if not np.isnan(value): if self._floatCut: value = self._floatRoundFormat % value else: value = None item.setData(self._role, value) def _newItemByRowKey(self, rowKey, col, value): if rowKey in self._itemsMap: row = self._itemsMap[rowKey][0].row() else: row = self.rowCount() if isinstance(col, str): col = self._getColPosWithCreation(col) # now we take it by positions item = self._updateItemByPos(row, col, value) # update to items map self._updateItemsMap(rowKey, col, item) def _updateItemByRowKey(self, rowKey, col, value): isExistingItem = False if rowKey in self._itemsMap: if isinstance(col, str): colPos = self._getColPos(col) else: colPos = col if colPos is not None: if colPos < len(self._itemsMap[rowKey]): if self._itemsMap[rowKey][ colPos] is not None: # item existing self._setItemData(self._itemsMap[rowKey][colPos], value) isExistingItem = True if not isExistingItem: self._newItemByRowKey(rowKey, col, value) def _updateItemByPos(self, row, col, value): # get item if existing item = self.item(row, col) # new item if item is None: # enlarge rowCount = self.rowCount() colCount = self.columnCount() if row >= rowCount: self.setRowCount(row + 1) if col >= colCount: self.setColumnCount(col + 1) # add new item item = DyTableWidgetItem(self._role) self.setItem(row, col, item) # Should call @setItem firstly, then set data self._setItemData(item, value) return item def _update(self, indices, value): """ Update one row by @indices is row key or row position, @value is [x, x, x, ...] or one item by @indices is (row key or row position, column name or column position), @value is x. position is from 0. """ if isinstance(indices, tuple): row, col = indices else: row, col = indices, None # add one row # update Org. if self.__index: if isinstance(row, str): # row key if row not in self._itemsMap: # first updating self._updateItem(row, 0, self.rowCount() + 1) else: if not self.item(row, 0): # first updating self._updateItem(row, 0, row + 1) # value is row No. from 1 offset = 1 # offset for column else: offset = 0 # offset for column if col is None: # row for col, v in enumerate(value, offset): self._updateItem(row, col, v) else: # one item self._updateItem(row, (col + offset) if isinstance(col, int) else col, value) def __setitem__(self, indices, value): """ add one row like obj[x] = [v,v,..] add one like obj[x,y] = v """ self.setSortingEnabled(False) self._update(indices, value) self.resizeColumnsToContents() self.resizeRowsToContents() self.setSortingEnabled(True) def addColNames(self, names): colStart = self.columnCount() self.setColumnCount(colStart + len(names)) for col, name in enumerate(names, colStart): colItem = self.horizontalHeaderItem(col) if colItem is None: colItem = QTableWidgetItem(col) self.setHorizontalHeaderItem(col, colItem) colItem.setText(name) #self.resizeColumnsToContents() def hasIndex(self): return self.__index def addColName(self, col, name): if self.__index: col += 1 if col >= self.columnCount(): self.setColumnCount(col + 1) colItem = self.horizontalHeaderItem(col) if colItem is None: colItem = QTableWidgetItem(col) self.setHorizontalHeaderItem(col, colItem) colItem.setText(name) #self.resizeColumnsToContents() def setHeaderForeground(self, color): """ 只能设置整个header http://stackoverflow.com/questions/36196988/color-individual-horizontal-headers-of-qtablewidget-in-pyqt @color: string, like 'red' """ self.horizontalHeader().setStyleSheet('color:' + color) def setColName(self, col, name): if self.__index: col += 1 colItem = self.horizontalHeaderItem(col) if colItem: colItem.setText(name) self.resizeColumnsToContents() def setColNames(self, names=None): """ @names:[name1, name2] """ if names is None: return if self.__index: newNames = ['Org.'] + names else: newNames = names self.setColumnCount(len(newNames)) self.setHorizontalHeaderLabels(newNames) self.resizeColumnsToContents() def setItemForeground(self, row, col, color): if self.__index: col += 1 try: self.item(row, col).setForeground(color) except Exception as ex: pass def setItemBackground(self, row, col, color): if self.__index: col += 1 try: self.item(row, col).setBackground(color) except Exception as ex: pass def setRowForeground(self, row, color): try: colCount = self.columnCount() start, end = (1, colCount) if self.__index else (0, colCount) for col in range(start, end): self.item(row, col).setForeground(color) except Exception as ex: pass def setRowBackground(self, row, color): try: colCount = self.columnCount() start, end = (1, colCount) if self.__index else (0, colCount) for col in range(start, end): self.item(row, col).setBackground(color) except Exception as ex: pass def append(self, rows, header=None, autoForegroundColName=None): """ @rows: [[x,x,x],[x,x,x],...] @header: [x,x,x] """ self.setSortingEnabled(False) if header: self.setColNames(header) if autoForegroundColName: self.setAutoForegroundCol(autoForegroundColName) rowCount = self.rowCount() self.setRowCount(rowCount + len(rows)) for rowIndex, rowData in enumerate(rows, rowCount): self._update(rowIndex, rowData) self.resizeColumnsToContents() self.resizeRowsToContents() self.setSortingEnabled(True) def appendRow(self, row, new=False, disableSorting=True): """ @row: [x,x,x] @return: row position of added row(starting from 0) """ if disableSorting: self.setSortingEnabled(False) if new: self.clearAllRows() rowCount = self.rowCount() self._update(rowCount, row) self.resizeColumnsToContents() self.resizeRowsToContents() if disableSorting: self.setSortingEnabled(True) return rowCount def setAutoForegroundCol(self, colName): self._autoForegroundCol = self._getColPos(colName) def getAutoForegroundColName(self): if self._autoForegroundCol is None: return None autoForegroundCol = self._autoForegroundCol - 1 if self.__index else self._autoForegroundCol return self.getColName(autoForegroundCol) def _autoScrollAct(self): self._enableAutoScroll = not self._enableAutoScroll if self._enableAutoScroll: self._autoScrollAction.setText('关闭自动滚动') else: self._autoScrollAction.setText('开启自动滚动') def _visibleMarkAct(self): if self._markedItem is not None: self.scrollToItem(self._markedItem) def _isInHighlight(self, item): row = item.row() for highlightedItems in self._highlightedItems: if highlightedItems[0].row() == row: return True return False def _setMark(self): row = self._markedItem.row() markBg = QColor(Qt.yellow) self.setRowBackground(row, markBg) for col in range(self.columnCount()): if self.__index and col == 0: self._markedItemsOriginalForeground.append(None) continue item = self.item(row, col) fg = item.foreground().color() # only change qdarkstyle default foreground if fg == QColor(0, 0, 0) or fg == QColor(192, 192, 192): item.setForeground(QColor(0, 0, 0)) # for qdarkstyle default foreground if fg == QColor(0, 0, 0): fg = QColor(192, 192, 192) # save self._markedItemsOriginalForeground.append(fg) def _setHighlight(self, item): row = item.row() highlightedItemsForeground = [] highlightedItemsBackground = [] self._highlightedItems.append( [item, highlightedItemsForeground, highlightedItemsBackground]) for col in range(self.columnCount()): if self.__index and col == 0: highlightedItemsForeground.append(None) highlightedItemsBackground.append(None) continue item = self.item(row, col) fg = item.foreground().color() bg = item.background() # only change qdarkstyle default foreground if fg == QColor(0, 0, 0) or fg == QColor(192, 192, 192): item.setForeground(QColor(0, 0, 0)) # for qdarkstyle default foreground if fg == QColor(0, 0, 0): fg = QColor(192, 192, 192) item.setBackground(self.highlightBackground) # save highlightedItemsForeground.append(fg) highlightedItemsBackground.append(bg) def _resetMark(self): row = self._markedItem.row() self.setRowBackground(row, self._markedItemOriginalBackground) for col in range(self.columnCount()): if self.__index and col == 0: continue item = self.item(row, col) # 如果标记后添加列,可能会导致超出 if col < len(self._markedItemsOriginalForeground): item.setForeground(self._markedItemsOriginalForeground[col]) def _resetHighlight(self, highlightItem): row = highlightItem[0].row() for col in range(self.columnCount()): if self.__index and col == 0: continue item = self.item(row, col) # 如果标记后添加列,可能会导致超出 if col < len(highlightItem[1]): item.setForeground(highlightItem[1][col]) # 如果标记后添加列,可能会导致超出 if col < len(highlightItem[2]): item.setBackground(highlightItem[2][col]) def markByData(self, colName, itemData): """ @colName: 指定item所在的列名 @itemData: item的数据 """ col = self._getColPos(colName) if col is None: return for row in range(self.rowCount()): if self[row, col] == itemData: item = self.item(row, col) self._mark(item) break def _highlightSameItemContent(self, item, clearHightlight=True): """ @clearHightlight: 是否清除先前的高亮 """ if item is None: return if clearHightlight: self._clearHighlight() text = item.text() col = item.column() for row in range(self.rowCount()): item = self.item(row, col) if item.text() == text: self._highlight(item, withCancel=False) def _highlight(self, item, withCancel=True): """ @withCancel: True-对已经高亮的item高亮,则清除该高亮 """ if item is None: return row = item.row() if self._markedItem is not None and self._markedItem.row() == row: return # 取消鼠标所在行的高亮 cancelHighlight = False for i, highlightedItem in enumerate(self._highlightedItems): if highlightedItem[0].row() == row: # 已经高亮过了 if not withCancel: return self._resetHighlight(highlightedItem) cancelHighlight = True break if cancelHighlight: del self._highlightedItems[i] return # highlight self._setHighlight(item) def _mark(self, item): if item is None: return if self._isInHighlight(item): return # 取消鼠标所在行的标记 if self._markedItem is not None and self._markedItem.row() == item.row( ): self._resetMark() self._markedItem = None self._markedItemsOriginalForeground = [] return # unmark previous if self._markedItem is not None: self._resetMark() self._markedItem = None self._markedItemsOriginalForeground = [] # save for new mark self._markedItemOriginalBackground = item.background() self._markedItem = item self._setMark() def _markAct(self): item = self.itemAt(self._rightClickPoint) self._mark(item) def _highlightAct(self): item = self.itemAt(self._rightClickPoint) self._highlight(item) def _highlightSameItemContentAct(self): item = self.itemAt(self._rightClickPoint) clearAction, notClearAction = self._highlightSameItemContentActions if notClearAction.isChecked(): notClearAction.setChecked(False) clearHighlight = False else: clearAction.setChecked(False) clearHighlight = True self._highlightSameItemContent(item, clearHighlight) def _initItemMenu(self): """ 初始化Item右键菜单 """ self._itemMenu = QMenu(self) self._tableCountAction = QAction('', self) self._itemMenu.addAction(self._tableCountAction) self._itemMenu.addSeparator() self._autoScrollAction = QAction( '关闭自动滚动' if self._enableAutoScroll else '开启自动滚动', self) self._autoScrollAction.triggered.connect(self._autoScrollAct) self._itemMenu.addAction(self._autoScrollAction) self._markAction = QAction('标记', self) self._markAction.triggered.connect(self._markAct) self._itemMenu.addAction(self._markAction) self._visibleMarkAction = QAction('定位到标记', self) self._visibleMarkAction.triggered.connect(self._visibleMarkAct) self._itemMenu.addAction(self._visibleMarkAction) # item只有一种状态,要不是标记,要不就是高亮 self._highlightAction = QAction('高亮', self) self._highlightAction.triggered.connect(self._highlightAct) self._itemMenu.addAction(self._highlightAction) # 高亮所有同列相同内容的item menu = self._itemMenu.addMenu('高亮同列相同内容的表项') self._highlightSameItemContentActions = [ QAction('清除先前高亮', self), QAction('保留先前高亮', self) ] for action in self._highlightSameItemContentActions: action.triggered.connect(self._highlightSameItemContentAct) action.setCheckable(True) menu.addAction(action) action = QAction('查找...', self) action.triggered.connect(self._findAct) self._itemMenu.addAction(action) def _findAct(self): data = {} if DySingleEditDlg(data, '查找', '要查找的内容').exec_(): text = str(data['data']) self._findItems = self.findItems(text, Qt.MatchContains) self._curFindItemPos = 0 if self._findItems: self.scrollToItem(self._findItems[self._curFindItemPos]) self.setCurrentItem(self._findItems[self._curFindItemPos]) else: QMessageBox.warning(self, '警告', '没有找到要查找的内容!') def keyPressEvent(self, event): if event.key() == Qt.Key_F3: if not self._findItems: QMessageBox.warning(self, '警告', '没有找到要查找的内容!') return self._curFindItemPos += 1 self._curFindItemPos = self._curFindItemPos % len(self._findItems) self.scrollToItem(self._findItems[self._curFindItemPos]) self.setCurrentItem(self._findItems[self._curFindItemPos]) def contextMenuEvent(self, event): """ Item右键点击事件 """ self._rightClickPoint = event.pos() item = self.itemAt(self._rightClickPoint) self._tableCountAction.setText('行: {0}, 列: {1}'.format( self.rowCount(), self.columnCount())) if item is None: self._markAction.setEnabled(False) self._highlightAction.setEnabled(False) else: itemState = 0 # 0: not marked or highlighted, 1: marked, 2: highlighted if self._markedItem is not None and self._markedItem.row( ) == item.row(): itemState = 1 else: for highlightedItem in self._highlightedItems: if highlightedItem[0].row() == item.row(): itemState = 2 if itemState == 0: self._markAction.setText('标记') self._markAction.setEnabled(True) self._highlightAction.setText('高亮') self._highlightAction.setEnabled(True) elif itemState == 1: self._markAction.setText('取消标记') self._markAction.setEnabled(True) self._highlightAction.setEnabled(False) else: self._highlightAction.setText('取消高亮') self._highlightAction.setEnabled(True) self._markAction.setEnabled(False) # at last, set visible mark action if self._markedItem is not None: self._visibleMarkAction.setText('定位标记') self._visibleMarkAction.setEnabled(True) else: self._visibleMarkAction.setEnabled(False) self._itemMenu.popup(QCursor.pos()) def removeRow(self, row): """ remove row, which can be by index or key """ self.setSortingEnabled(False) if isinstance(row, int): # remove by index # find item in map delRowKey = None for rowKey, items in self._itemsMap.items(): if items[0].row() == row: delRowKey = rowKey break # remove from map if delRowKey is not None: del self._itemsMap[delRowKey] # remove from table widget super().removeRow(row) else: # remove by key # remove from map if row in self._itemsMap: delRow = self._itemsMap[row][0].row() del self._itemsMap[row] # remove from table widget super().removeRow(delRow) self.setSortingEnabled(True) def removeAll(self): rowCount = self.rowCount() for _ in range(rowCount): self.removeRow(0) def getAll(self): """ 以列表方式返回table的所有值,Org.列除外 """ tableItems = [] for row in range(self.rowCount()): rowItems = [] colCount = (self.columnCount() - 1) if self.__index else self.columnCount() for col in range(colCount): rowItems.append(self[row, col]) tableItems.append(rowItems) return tableItems def getHighlights(self): """ 以列表方式返回table所有高亮的值,Org.列除外 """ # get sorted highlighed rows highlightedRows = [item[0].row() for item in self._highlightedItems] highlightedRows.sort() tableItems = [] for row in highlightedRows: rowItems = [] colCount = (self.columnCount() - 1) if self.__index else self.columnCount() for col in range(colCount): rowItems.append(self[row, col]) tableItems.append(rowItems) return tableItems def toDataFrame(self): colNames = self.getColNames() rows = self.getAll() df = pd.DataFrame(rows, columns=colNames) return df def getColNames(self): colNames = [] for col in range(self.columnCount()): headerItem = self.horizontalHeaderItem(col) colName = headerItem.text() if colName == 'Org.': continue colNames.append(colName) return colNames if colNames else None def getColName(self, col): if self.__index: col += 1 headerItem = self.horizontalHeaderItem(col) if headerItem: return headerItem.text() return None def getColumnsData(self, colNames): """ 以列表方式返回指定列名的所有值 @colNames: [colName] @return: [[data]] """ # get postions of column names colPos = [self._getColPos(x) for x in colNames] colPos = [((x - 1) if self.__index else x) for x in colPos] tableItems = [] for row in range(self.rowCount()): rowItems = [] for col in colPos: rowItems.append(self[row, col]) tableItems.append(rowItems) return tableItems def appendColumns(self, columnNames, columnsData): """ @columnNames: [column name] @columnsData: [[column data]] """ self.setSortingEnabled(False) # adjust start column postion for appended columns colStart = (self.columnCount() - 1) if self.__index else self.columnCount() # append column names for col, name in enumerate(columnNames, colStart): self.addColName(col, name) # append columns data for row, rowData in enumerate(columnsData): for col, data in enumerate(rowData, colStart): self._update((row, col), data) self.resizeColumnsToContents() self.resizeRowsToContents() # 重新设置标记 self._renewMark() # 重新设置高亮 self._renewHighlight() self.setSortingEnabled(True) def _updateAutoForegroundColForeground(self, row): item = self.item(row, self._autoForegroundCol) if item is None: return try: value = float(item.data(self._role)) except Exception as ex: value = 0 # if referenced item doesn't have value or not number, think it as default 0. if value > 0: color = Qt.red elif value < 0: color = Qt.darkGreen else: if item.background() == Qt.white: # for qdarkstyle color = Qt.black else: color = QColor('#C0C0C0') item.setForeground(color) def updateAutoForegroundCol(self, colAbs): """ @colAbs: 更新自动前景色关键列,包含'Org.' column """ if isinstance(colAbs, str): self._autoForegroundCol = self._getColPos(colAbs) else: self._autoForegroundCol = colAbs if self._autoForegroundCol is None: return for row in range(self.rowCount()): # upate foreground of auto foreground column item self._updateAutoForegroundColForeground(row) refItem = self.item(row, self._autoForegroundCol) if refItem is None: continue for col in range(self.columnCount()): if self.__index and col == 0: # ignore 'Org.' column continue item = self.item(row, col) if item is None: continue item.setForeground(refItem.foreground()) def getForegroundOverride(self, value): """ 可由子类重载,这样可以根据不同的值设置不同的前景色 """ try: value = float(value) if value > 0: color = Qt.red elif value < 0: color = Qt.darkGreen else: color = None # default except Exception as ex: color = None return color def _getForeground(self, rowData, autoForegroundCol, item): # 如果@rowData的item个数小于等于@autoForegroundCol # 支持row数据比header少的状况 try: value = rowData[autoForegroundCol] color = self.getForegroundOverride(value) except Exception as ex: color = None if color is None: if item.background() == Qt.white: color = Qt.black else: # for qdarkstyle color = QColor(192, 192, 192) return color def _updateOrg(self, row): if not self.__index: return item = self.item(row, 0) if item is None: item = DyTableWidgetItem(self._role) self.setItem(row, 0, item) item.setData(self._role, row + 1) def clearAllRows(self): self._clearVisualEffects() self.setRowCount(0) self._initRows() def fastAppendRows(self, rows, autoForegroundColName=None, new=False): """ 快速批量添加行数据,忽略细节 调用之前,必须先设置header @new: 新建还是添加 """ self.setSortingEnabled(False) if new: self._clearVisualEffects() self.setRowCount(len(rows)) rowStart = 0 self._initRows() else: rowStart = self.rowCount() self.setRowCount(rowStart + len(rows)) if autoForegroundColName is not None: self._autoForegroundCol = self._getColPos(autoForegroundColName) # column position in input raw data(@rows) if self._autoForegroundCol is not None: autoForegroundCol = self._autoForegroundCol - 1 if self.__index else self._autoForegroundCol offset = 1 if self.__index else 0 item = None for row, rowData in enumerate(rows, rowStart): self._updateOrg(row) for col, value in enumerate(rowData, offset): # create new if not existing item = self.item(row, col) if item is None: item = DyTableWidgetItem(self._role) self.setItem(row, col, item) # set item data self._setItemDataFast(item, value) # set foreground if autoForegroundColName is not None and self._autoForegroundCol is not None: if col == offset: # only get auto foreground when begining of row color = self._getForeground(rowData, autoForegroundCol, item) item.setForeground(color) self.resizeColumnsToContents() self.resizeRowsToContents() self.setSortingEnabled(True) if self._enableAutoScroll and item is not None: self.scrollToItem(item) def fastAppendColumns(self, columnNames, columnsData): """ 快速批量添加列数据,忽略细节 @columnNames: [column name] @columnsData: [[column data]] """ self.setSortingEnabled(False) # adjust start column postion for appended columns colStart = self.columnCount() # append column names self.addColNames(columnNames) # append columns data for row, rowData in enumerate(columnsData): for col, value in enumerate(rowData, colStart): # create new if not existing item = self.item(row, col) if item is None: item = DyTableWidgetItem(self._role) self.setItem(row, col, item) # set item data self._setItemDataFast(item, value) # get item of auto foreground if self._autoForegroundCol is None: continue refItem = self.item(row, self._autoForegroundCol) if not refItem: continue # set forground same as reference item item.setForeground(refItem.foreground()) self.resizeColumnsToContents() self.resizeRowsToContents() # 重新设置标记 self._renewMark() # 重新设置高亮 self._renewHighlight() self.setSortingEnabled(True) def _renewMark(self): """ 重新设置标记 """ markedItem = self._markedItem # 先取消标记 self._mark(markedItem) # 设置标记 self._mark(markedItem) def _renewHighlight(self): """ 重新设置高亮 """ # reproduce highlighed items because during cancel highlight procedure element will be deleted from @self._highlightedItems highlightedItems = [item[0] for item in self._highlightedItems] for item in highlightedItems: # 先取消高亮 self._highlight(item) # 设置高亮 self._highlight(item) def setItemsForeground(self, rowKeys, colors): """ @rowKeys: [rowKey] or [row number] @colors: ((text, color)) or [[text, color]] """ for key in rowKeys: for col in range(self.columnCount()): item = self._getItem(key, col) if item is None: continue itemData = item.data(self._role) for text, color in colors: if isinstance(itemData, str) and text in itemData: item.setForeground(color) break def filter(self, filter, highlight=False): """ 根据filter表达式选取行数据,filter表达式是对列进行操作。对应的列为x[0], x[1], ... @return: 过滤出来的数据列表 """ # 取消高亮 self._clearHighlight() tableItems = [] for row in range(self.rowCount()): rowItems = [] colCount = (self.columnCount() - 1) if self.__index else self.columnCount() for col in range(colCount): rowItems.append(self[row, col]) # execute filter try: x = rowItems if not eval(filter): # some of elements are None continue except Exception as ex: continue if highlight: self._highlight(self.item(row, col)) tableItems.append(rowItems) return tableItems def org(self, row): if self.__index: return self[row, 'Org.'] return None def addColumnOperateColumns(self, exp): """ 根据exp表达式进行列运算(类似于Pandas),并添加列到table widget x代表table widget对应的DataFrame """ newColumnData = [] for row in range(self.rowCount()): rowItems = [] colCount = (self.columnCount() - 1) if self.__index else self.columnCount() for col in range(colCount): rowItems.append(self[row, col]) # execute exp x = rowItems try: value = eval(exp) except: value = None newColumnData.append([value]) # get column name x = self.getColNames() try: p = re.compile('x\[\d+\]') elements = p.findall(exp) elements_ = [] for v in elements: elements_.append('[' + eval(v) + ']') expFormat = p.sub('{}', exp) newColumnName = expFormat.format(*elements_) except: newColumnName = exp # add columns into table widget self.fastAppendColumns([newColumnName], newColumnData)