class WatchersWidget(QWidget): """ WatchersWidget Signals: onItemSelected(addr_str) - item dblclicked onItemAddClick Constants: MEMORY_ACCESS_READ = 1 MEMORY_ACCESS_WRITE = 2 MEMORY_ACCESS_EXECUTE = 4 MEMORY_WATCH_SINGLESHOT = 8 """ MEMORY_ACCESS_READ = 1 MEMORY_ACCESS_WRITE = 2 MEMORY_ACCESS_EXECUTE = 4 MEMORY_WATCH_SINGLESHOT = 8 onItemDoubleClicked = pyqtSignal(int, name='onItemDoubleClicked') onItemAdded = pyqtSignal(int, name='onItemAdded') onItemRemoved = pyqtSignal(int, name='onItemRemoved') def __init__(self, parent=None): # pylint: disable=too-many-statements super(WatchersWidget, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('WatchersWidget created before Dwarf exists') return self._uppercase_hex = True self.setAutoFillBackground(True) # connect to dwarf self._app_window.dwarf.onWatcherAdded.connect(self._on_watcher_added) self._app_window.dwarf.onWatcherRemoved.connect( self._on_watcher_removed) # setup our model self._watchers_model = QStandardItemModel(0, 5) self._watchers_model.setHeaderData(0, Qt.Horizontal, 'Address') self._watchers_model.setHeaderData(1, Qt.Horizontal, 'R') self._watchers_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._watchers_model.setHeaderData(2, Qt.Horizontal, 'W') self._watchers_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._watchers_model.setHeaderData(3, Qt.Horizontal, 'X') self._watchers_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._watchers_model.setHeaderData(4, Qt.Horizontal, 'S') self._watchers_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) # setup ui v_box = QVBoxLayout(self) v_box.setContentsMargins(0, 0, 0, 0) self.list_view = DwarfListView() self.list_view.setModel(self._watchers_model) self.list_view.header().setSectionResizeMode(0, QHeaderView.Stretch) self.list_view.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setSectionResizeMode( 3, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setSectionResizeMode( 4, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setStretchLastSection(False) self.list_view.doubleClicked.connect(self._on_item_dblclick) self.list_view.setContextMenuPolicy(Qt.CustomContextMenu) self.list_view.customContextMenuRequested.connect(self._on_contextmenu) v_box.addWidget(self.list_view) #header = QHeaderView(Qt.Horizontal, self) h_box = QHBoxLayout() h_box.setContentsMargins(5, 2, 5, 5) btn1 = QPushButton(QIcon(utils.resource_path('assets/icons/plus.svg')), '') btn1.setFixedSize(20, 20) btn1.clicked.connect(self._on_additem_clicked) btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')), '') btn2.setFixedSize(20, 20) btn2.clicked.connect(self.delete_items) btn3 = QPushButton( QIcon(utils.resource_path('assets/icons/trashcan.svg')), '') btn3.setFixedSize(20, 20) btn3.clicked.connect(self.clear_list) h_box.addWidget(btn1) h_box.addWidget(btn2) h_box.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred)) h_box.addWidget(btn3) # header.setLayout(h_box) # header.setFixedHeight(25) # v_box.addWidget(header) v_box.addLayout(h_box) # create a centered dot icon _section_width = self.list_view.header().sectionSize(2) self._new_pixmap = QPixmap(_section_width, 20) self._new_pixmap.fill(Qt.transparent) painter = QPainter(self._new_pixmap) rect = QRect((_section_width * 0.5), 0, 20, 20) painter.setBrush(QColor('#666')) painter.setPen(QColor('#666')) painter.drawEllipse(rect) self._dot_icon = QIcon(self._new_pixmap) # shortcuts shortcut_add = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_W), self._app_window, self._on_additem_clicked) shortcut_add.setAutoRepeat(False) self.setLayout(v_box) # ************************************************************************ # **************************** Properties ******************************** # ************************************************************************ @property def uppercase_hex(self): """ Addresses displayed lower/upper-case """ return self._uppercase_hex @uppercase_hex.setter def uppercase_hex(self, value): """ Addresses displayed lower/upper-case value - bool or str 'upper', 'lower' """ if isinstance(value, bool): self._uppercase_hex = value elif isinstance(value, str): self._uppercase_hex = (value == 'upper') # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def do_addwatcher_dlg(self, ptr=None): # pylint: disable=too-many-branches """ Shows AddWatcherDialog """ watcher_dlg = AddWatcherDialog(self, ptr) if watcher_dlg.exec_() == QDialog.Accepted: mem_r = watcher_dlg.acc_read.isChecked() mem_w = watcher_dlg.acc_write.isChecked() mem_x = watcher_dlg.acc_execute.isChecked() mem_s = watcher_dlg.singleshot.isChecked() ptr = watcher_dlg.text_field.toPlainText() if ptr: if isinstance(ptr, str): if ptr.startswith('0x') or ptr.startswith('#'): ptr = utils.parse_ptr(ptr) else: try: ptr = int(ptr, 10) except ValueError: pass # int now? if not isinstance(ptr, int): try: ptr = int( self._app_window.dwarf.dwarf_api( 'evaluatePtr', ptr), 16) except ValueError: ptr = 0 if ptr == 0: return if not self._app_window.dwarf.dwarf_api( 'isValidPointer', ptr): return else: return mem_val = 0 if mem_r: mem_val |= self.MEMORY_ACCESS_READ if mem_w: mem_val |= self.MEMORY_ACCESS_WRITE if mem_x: mem_val |= self.MEMORY_ACCESS_EXECUTE if mem_s: mem_val |= self.MEMORY_WATCH_SINGLESHOT self.add_address(ptr, mem_val, from_api=False) # return [ptr, mem_val] def add_address(self, ptr, flags, from_api=False): """ Adds Address to display ptr - str or int flags - int """ if isinstance(ptr, str): ptr = utils.parse_ptr(ptr) if not isinstance(flags, int): try: flags = int(flags, 10) except ValueError: flags = 3 if not from_api: # function was called directly so add it to dwarf if not self._app_window.dwarf.is_address_watched(ptr): self._app_window.dwarf.dwarf_api('addWatcher', [ptr, flags]) return # show header self.list_view.setHeaderHidden(False) # create items to add if self._uppercase_hex: str_frmt = '0x{0:X}' else: str_frmt = '0x{0:x}' addr = QStandardItem() addr.setText(str_frmt.format(ptr)) read = QStandardItem() write = QStandardItem() execute = QStandardItem() singleshot = QStandardItem() if flags & self.MEMORY_ACCESS_READ: read.setIcon(self._dot_icon) if flags & self.MEMORY_ACCESS_WRITE: write.setIcon(self._dot_icon) if flags & self.MEMORY_ACCESS_EXECUTE: execute.setIcon(self._dot_icon) if flags & self.MEMORY_WATCH_SINGLESHOT: singleshot.setIcon(self._dot_icon) # add items as new row on top self._watchers_model.insertRow( 0, [addr, read, write, execute, singleshot]) def remove_address(self, ptr, from_api=False): """ Remove Address from List """ if isinstance(ptr, str): ptr = utils.parse_ptr(ptr) if not from_api: # called somewhere so remove watcher in dwarf too self._app_window.dwarf.dwarf_api('removeWatcher', ptr) return str_frmt = '' if self._uppercase_hex: str_frmt = '0x{0:X}'.format(ptr) else: str_frmt = '0x{0:x}'.format(ptr) model = self.list_view.model() for item in range(model.rowCount()): if str_frmt == model.item(item).text(): model.removeRow(item) def delete_items(self): """ Delete selected Items """ model = self.list_view.model() index = self.list_view.selectionModel().currentIndex().row() if index != -1: ptr = model.item(index, 0).text() self.remove_address(ptr) def clear_list(self): """ Clear the List """ model = self.list_view.model() # go through all items and tell it gets removed for item in range(model.rowCount()): ptr = model.item(item, 0).text() self.remove_address(ptr) if model.rowCount() > 0: # something was wrong it should be empty model.removeRows(0, model.rowCount()) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_contextmenu(self, pos): index = self.list_view.indexAt(pos).row() glbl_pt = self.list_view.mapToGlobal(pos) context_menu = QMenu(self) context_menu.addAction('Add watcher', self._on_additem_clicked) if index != -1: context_menu.addSeparator() context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self._watchers_model.item(index, 0).text())) context_menu.addAction( 'Jump to address', lambda: self._app_window.jump_to_address( self._watchers_model.item(index, 0).text())) context_menu.addAction( 'Delete watcher', lambda: self.remove_address( self._watchers_model.item(index, 0).text())) if self.list_view.search_enabled: context_menu.addSeparator() context_menu.addAction('Search', self.list_view._on_cm_search) context_menu.exec_(glbl_pt) def _on_item_dblclick(self, model_index): row = self._watchers_model.itemFromIndex(model_index).row() if row != -1: ptr = self._watchers_model.item(row, 0).text() self.onItemDoubleClicked.emit(ptr) def _on_additem_clicked(self): if self._app_window.dwarf.pid == 0: return self.do_addwatcher_dlg() def _on_watcher_added(self, ptr, flags): """ Callback from Dwarf after Watcher is added """ ptr = utils.parse_ptr(ptr) # add to watcherslist self.add_address(ptr, flags, from_api=True) self.onItemAdded.emit(ptr) def _on_watcher_removed(self, ptr): """ Callback from Dwarf after watcher is removed """ ptr = utils.parse_ptr(ptr) # remove from list self.remove_address(ptr, from_api=True) self.onItemRemoved.emit(ptr)
class AddressList(MyTreeView): class Columns(IntEnum): TYPE = 0 ADDRESS = 1 LABEL = 2 COIN_BALANCE = 3 FIAT_BALANCE = 4 NUM_TXS = 5 filter_columns = [Columns.TYPE, Columns.ADDRESS, Columns.LABEL, Columns.COIN_BALANCE] ROLE_SORT_ORDER = Qt.UserRole + 1000 ROLE_ADDRESS_STR = Qt.UserRole + 1001 def __init__(self, parent): super().__init__(parent, self.create_menu, stretch_column=self.Columns.LABEL, editable_columns=[self.Columns.LABEL]) self.wallet = self.parent.wallet self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSortingEnabled(True) self.show_change = AddressTypeFilter.ALL # type: AddressTypeFilter self.show_used = AddressUsageStateFilter.ALL # type: AddressUsageStateFilter self.change_button = QComboBox(self) self.change_button.currentIndexChanged.connect(self.toggle_change) for addr_type in AddressTypeFilter.__members__.values(): # type: AddressTypeFilter self.change_button.addItem(addr_type.ui_text()) self.used_button = QComboBox(self) self.used_button.currentIndexChanged.connect(self.toggle_used) for addr_usage_state in AddressUsageStateFilter.__members__.values(): # type: AddressUsageStateFilter self.used_button.addItem(addr_usage_state.ui_text()) self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=self.ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.update() self.sortByColumn(self.Columns.TYPE, Qt.AscendingOrder) def get_toolbar_buttons(self): return QLabel(_("Filter:")), self.change_button, self.used_button def on_hide_toolbar(self): self.show_change = AddressTypeFilter.ALL # type: AddressTypeFilter self.show_used = AddressUsageStateFilter.ALL # type: AddressUsageStateFilter self.update() def save_toolbar_state(self, state, config): config.set_key('show_toolbar_addresses', state) def refresh_headers(self): fx = self.parent.fx if fx and fx.get_fiat_address_config(): ccy = fx.get_currency() else: ccy = _('Fiat') headers = { self.Columns.TYPE: _('Type'), self.Columns.ADDRESS: _('Address'), self.Columns.LABEL: _('Label'), self.Columns.COIN_BALANCE: _('Balance'), self.Columns.FIAT_BALANCE: ccy + ' ' + _('Balance'), self.Columns.NUM_TXS: _('Tx'), } self.update_headers(headers) def toggle_change(self, state: int): if state == self.show_change: return self.show_change = AddressTypeFilter(state) self.update() def toggle_used(self, state: int): if state == self.show_used: return self.show_used = AddressUsageStateFilter(state) self.update() @profiler def update(self): if self.maybe_defer_update(): return current_address = self.get_role_data_for_current_item(col=self.Columns.LABEL, role=self.ROLE_ADDRESS_STR) if self.show_change == AddressTypeFilter.RECEIVING: addr_list = self.wallet.get_receiving_addresses() elif self.show_change == AddressTypeFilter.CHANGE: addr_list = self.wallet.get_change_addresses() else: addr_list = self.wallet.get_addresses() self.proxy.setDynamicSortFilter(False) # temp. disable re-sorting after every change self.std_model.clear() self.refresh_headers() fx = self.parent.fx set_address = None addresses_beyond_gap_limit = self.wallet.get_all_known_addresses_beyond_gap_limit() for address in addr_list: num = self.wallet.get_address_history_len(address) label = self.wallet.get_label(address) c, u, x = self.wallet.get_addr_balance(address) balance = c + u + x is_used_and_empty = self.wallet.is_used(address) and balance == 0 if self.show_used == AddressUsageStateFilter.UNUSED and (balance or is_used_and_empty): continue if self.show_used == AddressUsageStateFilter.FUNDED and balance == 0: continue if self.show_used == AddressUsageStateFilter.USED_AND_EMPTY and not is_used_and_empty: continue if self.show_used == AddressUsageStateFilter.FUNDED_OR_UNUSED and is_used_and_empty: continue balance_text = self.parent.format_amount(balance, whitespaces=True) # create item if fx and fx.get_fiat_address_config(): rate = fx.exchange_rate() fiat_balance = fx.value_str(balance, rate) else: fiat_balance = '' labels = ['', address, label, balance_text, fiat_balance, "%d"%num] address_item = [QStandardItem(e) for e in labels] # align text and set fonts for i, item in enumerate(address_item): item.setTextAlignment(Qt.AlignVCenter) if i not in (self.Columns.TYPE, self.Columns.LABEL): item.setFont(QFont(MONOSPACE_FONT)) self.set_editability(address_item) address_item[self.Columns.FIAT_BALANCE].setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) # setup column 0 if self.wallet.is_change(address): address_item[self.Columns.TYPE].setText(_('change')) address_item[self.Columns.TYPE].setBackground(ColorScheme.YELLOW.as_color(True)) else: address_item[self.Columns.TYPE].setText(_('receiving')) address_item[self.Columns.TYPE].setBackground(ColorScheme.GREEN.as_color(True)) address_item[self.Columns.LABEL].setData(address, self.ROLE_ADDRESS_STR) address_path = self.wallet.get_address_index(address) address_item[self.Columns.TYPE].setData(address_path, self.ROLE_SORT_ORDER) address_path_str = self.wallet.get_address_path_str(address) if address_path_str is not None: address_item[self.Columns.TYPE].setToolTip(address_path_str) address_item[self.Columns.FIAT_BALANCE].setData(balance, self.ROLE_SORT_ORDER) # setup column 1 if self.wallet.is_frozen_address(address): address_item[self.Columns.ADDRESS].setBackground(ColorScheme.BLUE.as_color(True)) if address in addresses_beyond_gap_limit: address_item[self.Columns.ADDRESS].setBackground(ColorScheme.RED.as_color(True)) # add item count = self.std_model.rowCount() self.std_model.insertRow(count, address_item) address_idx = self.std_model.index(count, self.Columns.LABEL) if address == current_address: set_address = QPersistentModelIndex(address_idx) self.set_current_idx(set_address) # show/hide columns if fx and fx.get_fiat_address_config(): self.showColumn(self.Columns.FIAT_BALANCE) else: self.hideColumn(self.Columns.FIAT_BALANCE) self.filter() self.proxy.setDynamicSortFilter(True) def create_menu(self, position): from electrum_mona.wallet import Multisig_Wallet is_multisig = isinstance(self.wallet, Multisig_Wallet) can_delete = self.wallet.can_delete_address() selected = self.selected_in_column(self.Columns.ADDRESS) if not selected: return multi_select = len(selected) > 1 addrs = [self.item_from_index(item).text() for item in selected] menu = QMenu() if not multi_select: idx = self.indexAt(position) if not idx.isValid(): return item = self.item_from_index(idx) if not item: return addr = addrs[0] addr_column_title = self.std_model.horizontalHeaderItem(self.Columns.LABEL).text() addr_idx = idx.sibling(idx.row(), self.Columns.LABEL) self.add_copy_menu(menu, idx) menu.addAction(_('Details'), lambda: self.parent.show_address(addr)) persistent = QPersistentModelIndex(addr_idx) menu.addAction(_("Edit {}").format(addr_column_title), lambda p=persistent: self.edit(QModelIndex(p))) #menu.addAction(_("Request payment"), lambda: self.parent.receive_at(addr)) if self.wallet.can_export(): menu.addAction(_("Private key"), lambda: self.parent.show_private_key(addr)) if not is_multisig and not self.wallet.is_watching_only(): menu.addAction(_("Sign/verify message"), lambda: self.parent.sign_verify_message(addr)) menu.addAction(_("Encrypt/decrypt message"), lambda: self.parent.encrypt_message(addr)) if can_delete: menu.addAction(_("Remove from wallet"), lambda: self.parent.remove_address(addr)) addr_URL = block_explorer_URL(self.config, 'addr', addr) if addr_URL: menu.addAction(_("View on block explorer"), lambda: webopen(addr_URL)) if not self.wallet.is_frozen_address(addr): menu.addAction(_("Freeze"), lambda: self.parent.set_frozen_state_of_addresses([addr], True)) else: menu.addAction(_("Unfreeze"), lambda: self.parent.set_frozen_state_of_addresses([addr], False)) coins = self.wallet.get_spendable_coins(addrs) if coins: menu.addAction(_("Spend from"), lambda: self.parent.utxo_list.set_spend_list(coins)) run_hook('receive_menu', menu, addrs, self.wallet) menu.exec_(self.viewport().mapToGlobal(position)) def place_text_on_clipboard(self, text: str, *, title: str = None) -> None: if is_address(text): try: self.wallet.check_address_for_corruption(text) except InternalAddressCorruption as e: self.parent.show_error(str(e)) raise super().place_text_on_clipboard(text, title=title) def get_edit_key_from_coordinate(self, row, col): if col != self.Columns.LABEL: return None return self.get_role_data_from_coordinate(row, col, role=self.ROLE_ADDRESS_STR) def on_edited(self, idx, edit_key, *, text): self.parent.wallet.set_label(edit_key, text) self.parent.history_model.refresh('address label edited') self.parent.utxo_list.update() self.parent.update_completions()
class MainWindow(QMainWindow): """ The main window. """ def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setWindowTitle("VenviPy") self.resize(1100, 690) self.center() self.setWindowIcon(QIcon(":/img/profile.png")) self.setStyleSheet( """ QMenuBar { background-color: rgb(47, 52, 63); color: rgb(210, 210, 210) } QMenuBar::item { background-color: rgb(47, 52, 63); color: rgb(210, 210, 210) } QMenuBar::item::selected { background-color: rgb(72, 72, 82) } QMenu { background-color: rgb(47, 52, 63); color: rgb(210, 210, 210) } QMenu::item::selected { background-color: rgb(72, 72, 82) } QToolTip { background-color: rgb(47, 52, 63); border: rgb(47, 52, 63); color: rgb(210, 210, 210); padding: 2px; opacity: 325 } QTableView { gridline-color: rgb(230, 230, 230) } QTableView::item { selection-background-color: rgb(120, 120, 130); selection-color: rgb(255, 255, 255) } """ ) self.info_about_venvipy = InfoAboutVenviPy() self.venv_wizard = wizard.VenvWizard() # refresh venv table on wizard close self.venv_wizard.refresh.connect(self.pop_venv_table) # refresh interpreter table if 'py-installs' changes self.venv_wizard.update_table.connect(self.pop_interpreter_table) #]===================================================================[# #] ICONS [#==========================================================[# #]===================================================================[# python_icon = QIcon(":/img/python.png") find_icon = QIcon.fromTheme("edit-find") manage_icon = QIcon.fromTheme("insert-object") settings_icon = QIcon.fromTheme("preferences-system") new_icon = QIcon( self.style().standardIcon(QStyle.SP_FileDialogNewFolder) ) exit_icon = QIcon( self.style().standardIcon(QStyle.SP_BrowserStop) ) reload_icon = QIcon( self.style().standardIcon(QStyle.SP_BrowserReload) ) delete_icon = QIcon( self.style().standardIcon(QStyle.SP_TrashIcon) ) folder_icon = QIcon( self.style().standardIcon(QStyle.SP_DirOpenIcon) ) qt_icon = QIcon( self.style().standardIcon(QStyle.SP_TitleBarMenuButton) ) info_icon = QIcon( self.style().standardIcon(QStyle.SP_FileDialogInfoView) ) #]===================================================================[# #] LAYOUTS [#========================================================[# #]===================================================================[# centralwidget = QWidget(self) grid_layout = QGridLayout(centralwidget) v_layout_1 = QVBoxLayout() v_layout_2 = QVBoxLayout() h_layout_1 = QHBoxLayout() v_layout_1.setContentsMargins(12, 19, 5, -1) v_layout_2.setContentsMargins(-1, 4, 6, -1) # python logo self.logo = QLabel(centralwidget) self.logo.setPixmap(QPixmap(":/img/pypower.png")) self.logo.setAlignment(Qt.AlignRight) #]===================================================================[# #] BUTTONS [#========================================================[# #]===================================================================[# self.add_interpreter_button = QPushButton( "Add &Interpreter", centralwidget, statusTip="Add an Interpreter", clicked=self.add_interpreter ) self.add_interpreter_button.setMinimumSize(QSize(150, 0)) self.new_venv_button = QPushButton( "&New Venv", centralwidget, statusTip="Create a new virtual environment", clicked=self.venv_wizard.exec_ ) self.new_venv_button.setMinimumSize(QSize(135, 0)) #self.search_pypi_button = QPushButton( #"&Search PyPI", #centralwidget, #statusTip="Search the Python Package Index", #clicked=self.search_pypi #) self.exit_button = QPushButton( "Quit", centralwidget, statusTip="Quit Application", clicked=self.on_close ) self.active_dir_button = QToolButton( icon=folder_icon, toolTip="Switch directory", statusTip="Select another directory", clicked=self.select_active_dir ) self.active_dir_button.setFixedSize(30, 30) # use line edit to store the str self.directory_line = QLineEdit() self.reload_button = QToolButton( icon=reload_icon, toolTip="Reload", statusTip="Reload venv table content", clicked=self.pop_venv_table ) self.reload_button.setFixedSize(30, 30) #]===================================================================[# # spacer between manage button and exit button spacer_item_1 = QSpacerItem( 20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding ) #]===================================================================[# v_layout_2.addWidget(self.logo) v_layout_2.addWidget(self.add_interpreter_button) v_layout_2.addWidget(self.new_venv_button) #v_layout_2.addWidget(self.search_pypi_button) v_layout_2.addItem(spacer_item_1) v_layout_2.addWidget(self.exit_button) grid_layout.addLayout(v_layout_2, 0, 1, 1, 1) #]===================================================================[# #] TABLES [#=========================================================[# #]===================================================================[# # interpreter table header interpreter_table_label = QLabel( '<span style="font-size: 13pt;">\ <b>Available Interpreters</b>\ </span>', centralwidget ) # interpreter table self.interpreter_table = InterpreterTable( centralwidget, selectionBehavior=QAbstractItemView.SelectRows, editTriggers=QAbstractItemView.NoEditTriggers, alternatingRowColors=True, sortingEnabled=True, drop_item=self.pop_interpreter_table ) # hide vertical header self.interpreter_table.verticalHeader().hide() # adjust (horizontal) headers h_header_interpreter_table = self.interpreter_table.horizontalHeader() h_header_interpreter_table.setDefaultAlignment(Qt.AlignLeft) h_header_interpreter_table.setDefaultSectionSize(180) h_header_interpreter_table.setStretchLastSection(True) # set table view model self.model_interpreter_table = QStandardItemModel(0, 2, centralwidget) self.model_interpreter_table.setHorizontalHeaderLabels( ["Version", "Path"] ) self.interpreter_table.setModel(self.model_interpreter_table) #]===================================================================[# # spacer between interpreter table and venv table title spacer_item_2 = QSpacerItem( 20, 12, QSizePolicy.Minimum, QSizePolicy.Fixed ) #]===================================================================[# # venv table header self.venv_table_label = QLabel(centralwidget) # venv table self.venv_table = VenvTable( centralwidget, selectionBehavior=QAbstractItemView.SelectRows, editTriggers=QAbstractItemView.NoEditTriggers, alternatingRowColors=True, sortingEnabled=True, refresh=self.pop_venv_table ) # hide vertical header self.venv_table.verticalHeader().hide() # adjust horizontal headers h_header_venv_table = self.venv_table.horizontalHeader() h_header_venv_table.setDefaultAlignment(Qt.AlignLeft) h_header_venv_table.setStretchLastSection(True) # set table view model self.model_venv_table = QStandardItemModel(0, 3, centralwidget) self.model_venv_table.setHorizontalHeaderLabels( ["Venv", "Version", "Packages", "installed"] ) self.venv_table.setModel(self.model_venv_table) # adjust column width self.venv_table.setColumnWidth(0, 225) self.venv_table.setColumnWidth(1, 120) self.venv_table.setColumnWidth(2, 100) self.venv_table.setColumnWidth(3, 80) # add widgets to layout v_layout_1.addWidget(interpreter_table_label) v_layout_1.addWidget(self.interpreter_table) v_layout_1.addItem(spacer_item_2) v_layout_1.addLayout(h_layout_1) h_layout_1.addWidget(self.venv_table_label) h_layout_1.addWidget(self.reload_button) h_layout_1.addWidget(self.active_dir_button) v_layout_1.addWidget(self.venv_table) grid_layout.addLayout(v_layout_1, 0, 0, 1, 1) self.setCentralWidget(centralwidget) #]===================================================================[# #] ACTIONS [#========================================================[# #]===================================================================[# # create actions self.action_add_interpreter = QAction( find_icon, "Add &Interpreter", self, statusTip="Add an Interpreter", shortcut="Ctrl+I", triggered=self.add_interpreter ) self.action_new_venv = QAction( new_icon, "&New Venv", self, statusTip="Create a new virtual environment", shortcut="Ctrl+N", triggered=self.venv_wizard.exec_ ) #self.action_search_pypi = QAction( #manage_icon, #"&Search PyPI", #self, #statusTip="Search the Python Package Index", #shortcut="Ctrl+S", #triggered=self.search_pypi #) self.action_select_active_dir = QAction( folder_icon, "Change active &directory", self, statusTip="Change active directory", shortcut="Ctrl+D", triggered=self.select_active_dir ) self.action_exit = QAction( exit_icon, "&Quit", self, statusTip="Quit application", shortcut="Ctrl+Q", triggered=self.on_close ) self.action_about_venvipy = QAction( info_icon, "&About VenviPy", self, statusTip="About VenviPy", shortcut="Ctrl+A", triggered=self.info_about_venvipy.exec_ ) self.action_about_qt = QAction( qt_icon, "About &Qt", self, statusTip="About Qt", shortcut="Ctrl+Q", triggered=self.info_about_qt ) #]===================================================================[# #] MENUS [#==========================================================[# #]===================================================================[# status_bar = QStatusBar(self) self.setStatusBar(status_bar) menu_bar = QMenuBar(self) menu_bar.setGeometry(QRect(0, 0, 740, 24)) self.setMenuBar(menu_bar) menu_venv = QMenu("&Venv", menu_bar) menu_venv.addAction(self.action_add_interpreter) menu_venv.addSeparator() menu_venv.addAction(self.action_new_venv) menu_venv.addAction(self.action_select_active_dir) menu_venv.addSeparator() menu_venv.addAction(self.action_exit) menu_bar.addAction(menu_venv.menuAction()) #menu_extras = QMenu("&Extras", menu_bar) #menu_extras.addAction(self.action_search_pypi) #menu_bar.addAction(menu_extras.menuAction()) menu_help = QMenu("&Help", menu_bar) menu_help.addAction(self.action_about_venvipy) menu_help.addAction(self.action_about_qt) menu_bar.addAction(menu_help.menuAction()) msg_txt = ( "No suitable Python installation found!\n\n" "Please specify the path to a Python (>=3.3) \n" "installation or click 'Continue' to go on anyway.\n\n" ) self.msg_box = QMessageBox( QMessageBox.Critical, "VenviPy", msg_txt, QMessageBox.NoButton, self ) # check if any Python is installed if os.path.exists(get_data.DB_FILE): with open(get_data.DB_FILE, "r") as f: lines = f.readlines() if len(lines) < 2: self.launching_without_python() def launching_without_python(self): """If no Python was found run with features disabled. """ logger.warning("No suitable Python installation found") self.msg_box.addButton("&Select", QMessageBox.AcceptRole) self.msg_box.addButton("&Continue", QMessageBox.RejectRole) if self.msg_box.exec_() == QMessageBox.AcceptRole: # let user specify path to an interpreter self.add_interpreter() else: self.enable_features(False) def center(self): """Center window. """ qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def on_close(self): """Stop all threads, then close the application. """ self.venv_wizard.basic_settings.thread.exit() self.venv_table.thread.exit() self.close() def info_about_qt(self): """Open the "About Qt" dialog. """ QMessageBox.aboutQt(self) def add_interpreter(self): """Add a custom interpreter. """ if self.venv_wizard.basic_settings.select_python() != "": self.enable_features(True) def enable_features(self, state): """Enable or disable features. """ self.venv_table.setEnabled(state) #self.search_pypi_button.setEnabled(state) #self.action_search_pypi.setEnabled(state) @pyqtSlot() def pop_interpreter_table(self): """Populate the interpreter table view. """ get_data.ensure_dbfile() with open(get_data.DB_FILE, newline="") as cf: reader = csv.DictReader(cf, delimiter=",") self.model_interpreter_table.setRowCount(0) for info in reader: self.model_interpreter_table.insertRow(0) for i, text in enumerate( (info["PYTHON_VERSION"], info["PYTHON_PATH"]) ): self.model_interpreter_table.setItem( 0, i, QStandardItem(text) ) # also populate the combo box in wizard self.venv_wizard.basic_settings.pop_combo_box() def pop_venv_table(self): """Populate the venv table view. """ self.model_venv_table.setRowCount(0) for info in get_data.get_active_dir(): self.model_venv_table.insertRow(0) for i, text in enumerate(( info.venv_name, info.venv_version, info.site_packages, info.is_installed )): self.model_venv_table.setItem(0, i, QStandardItem(text)) def update_label(self): """ Show the currently selected folder containing virtual environments. """ head = ( '<span style="font-size: 13pt;">\ <b>Virtual environments:</b>\ </span>' ) no_folder = ( '<span style="font-size: 13pt; color: #ff0000;">\ <i> --- please select a folder containing virtual environments</i>\ </span>' ) with_folder = ( f'<span style="font-size: 13pt; color: #0059ff;">\ {get_data.get_active_dir_str()}\ </span>' ) if get_data.get_active_dir_str() != "": self.venv_table_label.setText(f"{head}{with_folder}") else: self.venv_table_label.setText(f"{head}{no_folder}") def select_active_dir(self): """ Select the active directory of which the content should be shown in venv table. """ directory = QFileDialog.getExistingDirectory( self, "Open a folder containing virtual environments" ) self.directory_line.setText(directory) active_file = os.path.expanduser("~/.venvipy/active") active_dir = self.directory_line.text() if active_dir != "": if os.path.exists(active_file): with open(active_file, "w") as f: f.write(active_dir) self.pop_venv_table() self.update_label() def search_pypi(self): """Search the Python Package Index. """ pass
class MainWindow(QMainWindow): BASE_DIR = os.path.dirname(os.path.abspath(__file__)) MAIN_UI_FILE = os.path.join(BASE_DIR, "main.ui") NEW_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "new_dish_popup.ui") NEW_DISH_MULTI_POPUP_UI_FILE = os.path.join(BASE_DIR, "new_dish_multi_popup.ui") NEW_DISH_DATA_POPUP_UI_FILE = os.path.join(BASE_DIR, "new_dish_data_popup.ui") MODIFY_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "modify_dish_popup.ui") DB_FILE = os.path.join(BASE_DIR, "restaurant.db") def __init__(self): super(MainWindow, self).__init__() # Initialize variable self.db_connection = None self.new_dish_popup = QWidget() self.new_dish_multi_popup = QWidget() self.new_dish_data_popup = QWidget() self.modify_dish_popup = QWidget() self.dish_table_model = QStandardItemModel(0, 6) self.dish_table_proxy = TableFilter() self.dish_data_table_model = QStandardItemModel(0, 6) self.dish_data_table_proxy = TableFilter() self.graph_chart = None self.graph_series = {} # Load UI designs uic.loadUi(self.MAIN_UI_FILE, self) uic.loadUi(self.NEW_DISH_POPUP_UI_FILE, self.new_dish_popup) uic.loadUi(self.NEW_DISH_MULTI_POPUP_UI_FILE, self.new_dish_multi_popup) uic.loadUi(self.NEW_DISH_DATA_POPUP_UI_FILE, self.new_dish_data_popup) uic.loadUi(self.MODIFY_DISH_POPUP_UI_FILE, self.modify_dish_popup) self.init_dish_table() self.init_dish_data_table() self.init_graph() # Connect to database self.init_db_connection() # MainWindow Bind action triggers self.action_new_dish.triggered.connect(self.show_new_dish_popup) self.action_new_dish_multi.triggered.connect( self.show_new_dish_multi_popup) self.action_new_data_multi.triggered.connect( lambda: self.modify_new_dish_data_popup_table(show=True)) self.tabWidget.currentChanged.connect(self.update_graph) # Dish Table filter bind self.dish_lineEdit.textChanged.connect( lambda text, col_idx=1: self.dish_table_proxy.set_col_regex_filter( col_idx, text)) self.lower_price_doubleSpinBox.valueChanged.connect( lambda value, col_idx=2: self.dish_table_proxy. set_col_number_filter(col_idx, value, -1)) self.higher_price_doubleSpinBox.valueChanged.connect( lambda value, col_idx=2: self.dish_table_proxy. set_col_number_filter(col_idx, -1, value)) self.lower_week_sell_spinBox.valueChanged.connect( lambda value, col_idx=3: self.dish_table_proxy. set_col_number_filter(col_idx, value, -1)) self.higher_week_sell_spinBox.valueChanged.connect( lambda value, col_idx=3: self.dish_table_proxy. set_col_number_filter(col_idx, -1, value)) # Dish Data Table filter bind self.lower_data_dateEdit.dateChanged.connect( lambda date, col_idx=1: self.dish_data_table_proxy. set_col_date_filter(col_idx, date, -1)) self.higher_data_dateEdit.dateChanged.connect( lambda date, col_idx=1: self.dish_data_table_proxy. set_col_date_filter(col_idx, -1, date)) self.data_lineEdit.textChanged.connect( lambda text, col_idx=2: self.dish_data_table_proxy. set_col_regex_filter(col_idx, text)) self.lower_data_doubleSpinBox.valueChanged.connect( lambda value, col_idx=3: self.dish_data_table_proxy. set_col_number_filter(col_idx, value, -1)) self.higher_data_doubleSpinBox.valueChanged.connect( lambda value, col_idx=3: self.dish_data_table_proxy. set_col_number_filter(col_idx, -1, value)) self.lower_data_spinBox.valueChanged.connect( lambda value, col_idx=4: self.dish_data_table_proxy. set_col_number_filter(col_idx, value, -1)) self.higher_data_spinBox.valueChanged.connect( lambda value, col_idx=4: self.dish_data_table_proxy. set_col_number_filter(col_idx, -1, value)) self.data_all_check_checkBox.stateChanged.connect( lambda state, col_idx=5: self.data_table_check_state( state, col_idx)) self.dish_data_table_model.itemChanged.connect(self.update_series) # Popup bind action triggers self.new_dish_popup.create_new_dish_btn.clicked.connect( self.create_new_dish) self.new_dish_multi_popup.pushButton_ok.clicked.connect( self.create_new_dish_multi) self.new_dish_data_popup.dateEdit.dateChanged.connect( self.modify_new_dish_data_popup_table) self.new_dish_data_popup.pushButton_ok.clicked.connect( self.create_new_dish_data) # Get current dishes self.load_dish_table() self.load_dish_data_table() self.new_dish_data_popup.dateEdit.setDate(QtCore.QDate.currentDate()) def init_dish_table(self): self.dish_tableView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) # Set Header data and stretch for col, col_name in enumerate( ["ID", "菜品", "价格", "近7天总售出", "操作", "备注"]): self.dish_table_model.setHeaderData(col, Qt.Horizontal, col_name, Qt.DisplayRole) self.dish_table_proxy.setSourceModel(self.dish_table_model) self.dish_tableView.setModel(self.dish_table_proxy) self.dish_tableView.setColumnHidden(0, True) for (col, method) in [(1, "Regex"), (2, "Number"), (3, "Number"), (5, "Regex")]: self.dish_table_proxy.filter_method[col] = method def init_dish_data_table(self): self.data_tableView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) for col, col_name in enumerate( ["Dish_ID", "日期", "菜品", "价格", "售出", "选择"]): self.dish_data_table_model.setHeaderData(col, Qt.Horizontal, col_name, Qt.DisplayRole) self.dish_data_table_proxy.setSourceModel(self.dish_data_table_model) self.data_tableView.setModel(self.dish_data_table_proxy) self.data_tableView.setColumnHidden(0, True) for (col, method) in [(1, "Date"), (2, "Regex"), (3, "Number"), (4, "Number")]: self.dish_data_table_proxy.filter_method[col] = method def init_graph(self): self.graph_chart = QChart(title="售出图") self.graph_chart.legend().setVisible(True) self.graph_chart.setAcceptHoverEvents(True) graph_view = QChartView(self.graph_chart) graph_view.setRenderHint(QPainter.Antialiasing) self.gridLayout_5.addWidget(graph_view) def init_db_connection(self): self.db_connection = sqlite3.connect(self.DB_FILE) cursor = self.db_connection.cursor() # check create table if not exist sql_create_dish_table = """ CREATE TABLE IF NOT EXISTS dish ( id integer PRIMARY KEY, name text NOT NULL, price numeric Not NULL, remarks text, UNIQUE (name, price) ); """ sql_create_dish_data_table = """ CREATE TABLE IF NOT EXISTS dish_data ( dish_id integer NOT NULL REFERENCES dish(id) ON DELETE CASCADE, date date, sell_num integer DEFAULT 0, PRIMARY KEY (dish_id, date), CONSTRAINT dish_fk FOREIGN KEY (dish_id) REFERENCES dish (id) ON DELETE CASCADE ); """ sql_trigger = """ CREATE TRIGGER IF NOT EXISTS place_holder_data AFTER INSERT ON dish BEGIN INSERT INTO dish_data (dish_id, date, sell_num) VALUES(new.id, null, 0); END; """ cursor.execute(sql_create_dish_table) cursor.execute(sql_create_dish_data_table) cursor.execute("PRAGMA FOREIGN_KEYS = on") cursor.execute(sql_trigger) cursor.close() def load_dish_table(self): today = datetime.today() sql_select_query = """ SELECT dish.id, dish.name, dish.price, COALESCE(SUM(dish_data.sell_num), 0), dish.remarks FROM dish LEFT JOIN dish_data ON dish.id = dish_data.dish_id WHERE dish_data.date IS NULL OR dish_data.date BETWEEN date('{}') and date('{}') GROUP BY dish.id ORDER BY dish.name, dish.price;""".format( (today - timedelta(days=7)).strftime("%Y-%m-%d"), today.strftime("%Y-%m-%d")) cursor = self.db_connection.cursor() cursor.execute(sql_select_query) records = cursor.fetchall() for row_idx, record in enumerate(records): self.dish_table_model.appendRow(create_dish_table_row(*record)) cursor.close() self.dish_tableView.setItemDelegateForColumn( 4, DishTableDelegateCell(self.show_modify_dish_popup, self.delete_dish, self.dish_tableView)) def load_dish_data_table(self): sql_select_query = """ SELECT dish_data.dish_id, dish_data.date, dish.name, dish.price, dish_data.sell_num FROM dish_data LEFT JOIN dish ON dish_data.dish_id = dish.id WHERE dish_data.date IS NOT NULL ORDER BY dish_data.date DESC, dish.name, dish.price, dish_data.sell_num;""" cursor = self.db_connection.cursor() cursor.execute(sql_select_query) records = cursor.fetchall() for row_idx, record in enumerate(records): self.dish_data_table_model.appendRow( create_dish_data_table_row(*record)) cursor.close() self.lower_data_dateEdit.setDate(QDate.currentDate().addDays(-7)) self.higher_data_dateEdit.setDate(QDate.currentDate()) self.data_tableView.setItemDelegateForColumn( 5, DishDataTableDelegateCell(self.data_tableView)) def data_table_check_state(self, state, col): for row in range(self.dish_data_table_proxy.rowCount()): index = self.dish_data_table_proxy.mapToSource( self.dish_data_table_proxy.index(row, col)) if index.isValid(): self.dish_data_table_model.setData(index, str(state), Qt.DisplayRole) def show_new_dish_popup(self): # Move popup to center point = self.rect().center() global_point = self.mapToGlobal(point) self.new_dish_popup.move( global_point - QtCore.QPoint(self.new_dish_popup.width() // 2, self.new_dish_popup.height() // 2)) self.new_dish_popup.show() def show_new_dish_multi_popup(self): file_name = QFileDialog().getOpenFileName(None, "选择文件", "", self.tr("CSV文件 (*.csv)"))[0] self.new_dish_multi_popup.tableWidget.setRowCount(0) if file_name: with open(file_name, "r") as file: csv_reader = csv.reader(file, delimiter=",") for idx, row_data in enumerate(csv_reader): if len(row_data) == 2: name, price = row_data remark = "" elif len(row_data) == 3: name, price, remark = row_data else: QMessageBox.warning( self, "格式错误", self.tr('格式为"菜品 价格"或者"菜品 价格 备注"\n第{}行输入有误'.format( idx))) return self.new_dish_multi_popup.tableWidget.insertRow( self.new_dish_multi_popup.tableWidget.rowCount()) self.new_dish_multi_popup.tableWidget.setItem( idx, 0, QTableWidgetItem(name)) price_type = str_type(price) if price_type == str or (isinstance( price_type, (float, int)) and float(price) < 0): QMessageBox.warning( self, "格式错误", self.tr('第{}行价格输入有误'.format(idx + 1))) return self.new_dish_multi_popup.tableWidget.setItem( idx, 1, QTableWidgetItem("{:.2f}".format(float(price)))) self.new_dish_multi_popup.tableWidget.setItem( idx, 2, QTableWidgetItem(remark)) self.new_dish_multi_popup.show() def modify_new_dish_data_popup_table(self, *args, show=False): sql_select_query = """ SELECT id, name, price, dish_data.sell_num FROM dish LEFT JOIN dish_data ON dish.id=dish_data.dish_id WHERE dish_data.date IS NULL OR dish_data.date = date('{}') GROUP BY id, name, price ORDER BY dish.name, dish.price;""".format( self.new_dish_data_popup.dateEdit.date().toString("yyyy-MM-dd")) cursor = self.db_connection.cursor() cursor.execute(sql_select_query) records = cursor.fetchall() self.new_dish_data_popup.tableWidget.setRowCount(len(records)) self.new_dish_data_popup.tableWidget.setColumnHidden(0, True) for row_idx, record in enumerate(records): dish_id, name, price, sell_num = record self.new_dish_data_popup.tableWidget.setItem( row_idx, 0, QTableWidgetItem(str(dish_id))) self.new_dish_data_popup.tableWidget.setItem( row_idx, 1, QTableWidgetItem(name)) self.new_dish_data_popup.tableWidget.setItem( row_idx, 2, QTableWidgetItem("{:.2f}".format(price))) spin_box = QSpinBox() spin_box.setMaximum(9999) spin_box.setValue(sell_num) self.new_dish_data_popup.tableWidget.setCellWidget( row_idx, 3, spin_box) cursor.close() if show: self.new_dish_data_popup.show() def create_new_dish(self): cursor = self.db_connection.cursor() sql_insert = """ INSERT INTO dish(name, price, remarks) VALUES(?,?,?)""" dish_name = self.new_dish_popup.dish_name.text() dish_price = self.new_dish_popup.dish_price.value() dish_remark = self.new_dish_popup.dish_remark.toPlainText() try: cursor.execute(sql_insert, (dish_name, dish_price, dish_remark)) new_dish_id = cursor.lastrowid cursor.close() self.db_connection.commit() # Update dish table and dish comboBox in UI self.dish_table_model.appendRow( create_dish_table_row(new_dish_id, dish_name, dish_price, 0, dish_remark)) self.new_dish_popup.hide() except sqlite3.Error: cursor.close() QMessageBox.warning(self, "菜品价格重复", self.tr('菜品价格组合重复,请检查')) def create_new_dish_multi(self): cursor = self.db_connection.cursor() sql_insert = """ INSERT INTO dish(name, price, remarks) VALUES (?, ?, ?)""" for row in range(self.new_dish_multi_popup.tableWidget.rowCount()): dish_name = self.new_dish_multi_popup.tableWidget.item(row, 0).text() dish_price = float( self.new_dish_multi_popup.tableWidget.item(row, 1).text()) dish_remark = self.new_dish_multi_popup.tableWidget.item(row, 2).text() try: cursor.execute(sql_insert, (dish_name, dish_price, dish_remark)) new_dish_id = cursor.lastrowid self.dish_table_model.appendRow( create_dish_table_row(new_dish_id, dish_name, dish_price, 0, dish_remark)) except sqlite3.Error: cursor.close() QMessageBox.warning( self, "菜品价格重复", self.tr('前{}行已插入。\n第{}行菜品价格组合重复,请检查'.format(row, row + 1))) return cursor.close() self.db_connection.commit() self.new_dish_multi_popup.hide() def create_new_dish_data(self): current_date = self.new_dish_data_popup.dateEdit.date().toString( "yyyy-MM-dd") table_filter = TableFilter() table_filter.setSourceModel(self.dish_data_table_model) table_filter.set_col_regex_filter(1, current_date) for row in range(table_filter.rowCount()): index = table_filter.mapToSource(table_filter.index(0, 1)) if index.isValid(): self.dish_data_table_model.removeRow(index.row()) del table_filter cursor = self.db_connection.cursor() sql_insert = """ INSERT OR REPLACE INTO dish_data(dish_id, date, sell_num) VALUES (?, ?, ?)""" for row in range(self.new_dish_data_popup.tableWidget.rowCount()): dish_id = int( self.new_dish_data_popup.tableWidget.item(row, 0).text()) name = self.new_dish_data_popup.tableWidget.item(row, 1).text() price = float( self.new_dish_data_popup.tableWidget.item(row, 2).text()) sell_num = self.new_dish_data_popup.tableWidget.cellWidget( row, 3).value() cursor.execute(sql_insert, (dish_id, current_date, sell_num)) self.dish_data_table_model.appendRow( create_dish_data_table_row(dish_id, current_date, name, price, sell_num)) cursor.close() self.db_connection.commit() self.new_dish_data_popup.hide() def delete_dish(self, dish_id): cursor = self.db_connection.cursor() sql_delete = """ DELETE FROM dish WHERE id=?""" cursor.execute(sql_delete, tuple([dish_id])) cursor.close() self.db_connection.commit() # Update dish table and dish comboBox in UI for row in self.dish_data_table_model.findItems(str(dish_id)): index = row.index() if index.isValid(): self.dish_data_table_model.removeRow(index.row()) for row in self.dish_table_model.findItems(str(dish_id)): index = row.index() if index.isValid(): self.dish_table_model.removeRow(index.row()) def show_modify_dish_popup(self, dish_id): point = self.rect().center() global_point = self.mapToGlobal(point) self.modify_dish_popup.move( global_point - QtCore.QPoint(self.modify_dish_popup.width() // 2, self.modify_dish_popup.height() // 2)) # Find the row and get necessary info index = self.dish_table_model.match(self.dish_table_model.index(0, 0), Qt.DisplayRole, str(dish_id)) if index: row_idx = index[0] dish_name = self.dish_table_model.data(row_idx.siblingAtColumn(1)) dish_price = self.dish_table_model.data(row_idx.siblingAtColumn(2)) dish_remark = self.dish_table_model.data( row_idx.siblingAtColumn(5)) self.modify_dish_popup.dish_name.setText(dish_name) self.modify_dish_popup.dish_price.setValue(float(dish_price)) self.modify_dish_popup.dish_remark.setText(dish_remark) try: self.modify_dish_popup.modify_dish_btn.clicked.disconnect() except TypeError: pass self.modify_dish_popup.modify_dish_btn.clicked.connect( lambda: self.modify_dish(row_idx, dish_id)) self.modify_dish_popup.show() def modify_dish(self, row, dish_id): cursor = self.db_connection.cursor() sql_update = """ UPDATE dish SET name = ?, price = ?, remarks = ? WHERE id=?""" dish_name = self.modify_dish_popup.dish_name.text() dish_price = self.modify_dish_popup.dish_price.value() dish_remark = self.modify_dish_popup.dish_remark.toPlainText() cursor.execute(sql_update, (dish_name, dish_price, dish_remark, dish_id)) cursor.close() self.db_connection.commit() self.modify_dish_popup.hide() # Update dish table and dish comboBox in UI old_name = self.dish_table_model.data(row.siblingAtColumn(1)) old_price = self.dish_table_model.data(row.siblingAtColumn(2)) sell_num = self.dish_table_model.data(row.siblingAtColumn(3)) row_idx = row.row() self.dish_table_model.removeRow(row_idx) self.dish_table_model.insertRow( row_idx, create_dish_table_row(dish_id, dish_name, dish_price, sell_num, dish_remark)) for row in self.dish_data_table_model.findItems(str(dish_id)): index = row.index() if index.isValid(): self.dish_data_table_model.setData(index.siblingAtColumn(2), dish_name) self.dish_data_table_model.setData(index.siblingAtColumn(3), "{:.2f}".format(dish_price)) old_key = old_name + '(' + old_price + ')' if old_key in self.graph_line_series: self.graph_line_series[dish_name + '(' + str(dish_price) + ')'] = self.graph_line_series[old_key] del self.graph_line_series[old_key] def update_series(self, item: QStandardItem): if item.column() == 5: # check for checkbox column item_idx = item.index() date = self.dish_data_table_model.data(item_idx.siblingAtColumn(1)) dish_name = self.dish_data_table_model.data( item_idx.siblingAtColumn(2)) dish_price = self.dish_data_table_model.data( item_idx.siblingAtColumn(3)) sell_num = self.dish_data_table_model.data( item_idx.siblingAtColumn(4)) set_name = dish_name + "(" + dish_price + ")" key = str( QDateTime(QDate.fromString(date, "yyyy-MM-dd")).toSecsSinceEpoch()) if key not in self.graph_series: self.graph_series[key] = {} if int(item.text()) == 0: if set_name in self.graph_series[key]: del self.graph_series[key][set_name] if not self.graph_series[key]: del self.graph_series[key] else: self.graph_series[key][set_name] = int(sell_num) def update_graph(self, index): if index == 2: self.graph_chart.removeAllSeries() axis_x = QBarCategoryAxis() axis_x.setTitleText("日期") if self.graph_chart.axisX(): self.graph_chart.removeAxis(self.graph_chart.axisX()) self.graph_chart.addAxis(axis_x, Qt.AlignBottom) axis_y = QValueAxis() axis_y.setLabelFormat("%i") axis_y.setTitleText("售出量") if self.graph_chart.axisY(): self.graph_chart.removeAxis(self.graph_chart.axisY()) self.graph_chart.addAxis(axis_y, Qt.AlignLeft) max_num = 0 total_date = 0 set_dict = {} for key, data in sorted(self.graph_series.items(), key=lambda i: int(i[0])): axis_x.append( QDateTime.fromSecsSinceEpoch( int(key)).toString("yyyy年MM月dd日")) for set_name, value in data.items(): if set_name not in set_dict: set_dict[set_name] = QBarSet(set_name) for _ in range(total_date): set_dict[set_name].append(0) set_dict[set_name].append(value) max_num = max(max_num, value) total_date += 1 for _, bar_set in set_dict.items(): if bar_set.count() < total_date: bar_set.append(0) bar_series = QBarSeries() for _, bar_set in set_dict.items(): bar_series.append(bar_set) bar_series.hovered.connect(self.graph_tooltip) axis_y.setMax(max_num + 1) axis_y.setMin(0) self.graph_chart.addSeries(bar_series) bar_series.attachAxis(axis_x) bar_series.attachAxis(axis_y) def graph_tooltip(self, status, index, bar_set: QBarSet): if status: QToolTip.showText( QCursor.pos(), "{}\n日期: {}\n售出: {}".format(bar_set.label(), self.graph_chart.axisX().at(index), int(bar_set.at(index))))
class InvoiceList(MyTreeView): class Columns(IntEnum): DATE = 0 TX_TYPE = 1 DESCRIPTION = 2 AMOUNT = 3 IS_PS = 4 STATUS = 5 headers = { Columns.DATE: _('Date'), Columns.TX_TYPE: _('Type'), Columns.DESCRIPTION: _('Description'), Columns.AMOUNT: _('Amount'), Columns.IS_PS: _('PrivateSend'), Columns.STATUS: _('Status'), } filter_columns = [Columns.DATE, Columns.DESCRIPTION, Columns.AMOUNT, Columns.IS_PS, Columns.TX_TYPE] def __init__(self, parent): super().__init__(parent, self.create_menu, stretch_column=self.Columns.DESCRIPTION, editable_columns=[]) self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.setSortingEnabled(True) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.update() def update_item(self, key, invoice: Invoice): model = self.std_model for row in range(0, model.rowCount()): item = model.item(row, 0) if item.data(ROLE_REQUEST_ID) == key: break else: return status_item = model.item(row, self.Columns.STATUS) status = self.parent.wallet.get_invoice_status(invoice) status_str = invoice.get_status_str(status) status_item.setText(status_str) status_item.setIcon(read_QIcon(pr_icons.get(status))) def update(self): # not calling maybe_defer_update() as it interferes with conditional-visibility self.proxy.setDynamicSortFilter(False) # temp. disable re-sorting after every change self.std_model.clear() self.update_headers(self.__class__.headers) for idx, item in enumerate(self.parent.wallet.get_invoices()): key = item.id invoice_ext = self.parent.wallet.get_invoice_ext(key) icon_name = 'dashcoin.png' if item.bip70: icon_name = 'seal.png' status = self.parent.wallet.get_invoice_status(item) status_str = item.get_status_str(status) message = item.message amount = item.get_amount_sat() timestamp = item.time or 0 ps_str = _('PrivateSend') if invoice_ext.is_ps else _('Regular') tx_type = invoice_ext.tx_type type_str = SPEC_TX_NAMES[tx_type] date_str = format_time(timestamp) if timestamp else _('Unknown') amount_str = self.parent.format_amount(amount, whitespaces=True) labels = [date_str, type_str, message, amount_str, ps_str, status_str] items = [QStandardItem(e) for e in labels] self.set_editability(items) items[self.Columns.DATE].setIcon(read_QIcon(icon_name)) items[self.Columns.STATUS].setIcon(read_QIcon(pr_icons.get(status))) items[self.Columns.DATE].setData(key, role=ROLE_REQUEST_ID) items[self.Columns.DATE].setData(item.type, role=ROLE_REQUEST_TYPE) items[self.Columns.DATE].setData(timestamp, role=ROLE_SORT_ORDER) items[self.Columns.TX_TYPE].setData(type_str, role=ROLE_SORT_ORDER) items[self.Columns.IS_PS].setData(ps_str, role=ROLE_SORT_ORDER) self.std_model.insertRow(idx, items) self.filter() self.proxy.setDynamicSortFilter(True) # sort requests by date self.sortByColumn(self.Columns.DATE, Qt.DescendingOrder) # hide list if empty if self.parent.isVisible(): b = self.std_model.rowCount() > 0 self.setVisible(b) self.parent.invoices_label.setVisible(b) def create_menu(self, position): wallet = self.parent.wallet items = self.selected_in_column(0) if len(items)>1: keys = [ item.data(ROLE_REQUEST_ID) for item in items] invoices = [ wallet.invoices.get(key) for key in keys] invoices_ext = [ wallet.invoices_ext.get(key) for key in keys] can_batch_pay = all([i.type == PR_TYPE_ONCHAIN and wallet.get_invoice_status(i) == PR_UNPAID for i in invoices]) if can_batch_pay: if any([i.is_ps for i in invoices_ext]): can_batch_pay = False if can_batch_pay: if any([(i.tx_type or i.extra_payload) for i in invoices_ext]): can_batch_pay = False menu = QMenu(self) if can_batch_pay: menu.addAction(_("Batch pay invoices") + "...", lambda: self.parent.pay_multiple_invoices(invoices)) menu.addAction(_("Delete invoices"), lambda: self.parent.delete_invoices(keys)) menu.exec_(self.viewport().mapToGlobal(position)) return idx = self.indexAt(position) item = self.item_from_index(idx) item_col0 = self.item_from_index(idx.sibling(idx.row(), self.Columns.DATE)) if not item or not item_col0: return key = item_col0.data(ROLE_REQUEST_ID) invoice = self.parent.wallet.get_invoice(key) menu = QMenu(self) self.add_copy_menu(menu, idx) if len(invoice.outputs) == 1: menu.addAction(_("Copy Address"), lambda: self.parent.do_copy(invoice.get_address(), title='Dash Address')) menu.addAction(_("Details"), lambda: self.parent.show_onchain_invoice(invoice)) status = wallet.get_invoice_status(invoice) if status == PR_UNPAID: menu.addAction(_("Pay") + "...", lambda: self.parent.do_pay_invoice(invoice)) if status == PR_FAILED: menu.addAction(_("Retry"), lambda: self.parent.do_pay_invoice(invoice)) menu.addAction(_("Delete"), lambda: self.parent.delete_invoices([key])) menu.exec_(self.viewport().mapToGlobal(position))
class MainWindow(QWidget): Id, Password = range(2) CONFIG_FILE = 'config' def __init__(self): super().__init__() with open(self.CONFIG_FILE, 'a'): pass self.init() def init(self): # ------ initUI self.resize(555, 245) self.setFixedSize(555, 245) self.center() self.setWindowTitle('Portal Connector') self.setWindowIcon(QIcon('gao.ico')) self.backgroundRole() palette1 = QPalette() palette1.setColor(self.backgroundRole(), QColor(250, 250, 250)) # 设置背景颜色 self.setPalette(palette1) # ------setLeftWidget self.dataGroupBox = QGroupBox("Saved", self) self.dataGroupBox.setGeometry(10, 10, 60, 20) self.dataGroupBox.setStyleSheet(MyGroupBox) self.model = QStandardItemModel(0, 2, self) self.model.setHeaderData(self.Id, Qt.Horizontal, "Id") self.model.setHeaderData(self.Password, Qt.Horizontal, "Pw") self.dataView = QTreeView(self) self.dataView.setGeometry(10, 32, 255, 150) self.dataView.setRootIsDecorated(False) self.dataView.setAlternatingRowColors(True) self.dataView.setModel(self.model) self.dataView.setStyleSheet(MyTreeView) save_btn = QPushButton('Save', self) save_btn.setGeometry(15, 195, 100, 35) save_btn.setStyleSheet(MyPushButton) delete_btn = QPushButton('Delete', self) delete_btn.setGeometry(135, 195, 100, 35) delete_btn.setStyleSheet(MyPushButton) # ------ setRightWidget username = QLabel('Id:', self) username.setGeometry(300, 45, 50, 30) username.setStyleSheet(MyLabel) self.username_edit = QLineEdit(self) self.username_edit.setGeometry(350, 40, 190, 35) self.username_edit.setStyleSheet(MyLineEdit) password = QLabel('Pw:', self) password.setGeometry(300, 100, 50, 30) password.setStyleSheet(MyLabel) self.password_edit = QLineEdit(self) self.password_edit.setGeometry(350, 95, 190, 35) self.password_edit.setStyleSheet(MyLineEdit) status_label = QLabel('Result:', self) status_label.setGeometry(295, 150, 70, 30) status_label.setStyleSheet(UnderLabel) self.status = QLabel('Disconnect', self) self.status.setGeometry(360, 150, 190, 30) self.status.setStyleSheet(UnderLabel) connect_btn = QPushButton('Connect', self) connect_btn.setGeometry(320, 195, 100, 35) connect_btn.setStyleSheet(MyPushButton) test_btn = QPushButton('Test', self) test_btn.setGeometry(440, 195, 100, 35) test_btn.setStyleSheet(MyPushButton) # ------setTabOrder self.setTabOrder(self.username_edit, self.password_edit) self.setTabOrder(self.password_edit, connect_btn) self.setTabOrder(connect_btn, test_btn) # ------setEvent self.dataView.mouseDoubleClickEvent = self.set_text self.dataView.mousePressEvent = self.set_focus delete_btn.clicked.connect(self.removeItem) connect_btn.clicked.connect(self.connect_clicked) save_btn.clicked.connect(self.save_infomation) test_btn.clicked.connect(self.test_network) self.readItem(self.CONFIG_FILE) self.connect_clicked() self.show() def connect_clicked(self): result = connect_portal(self.username_edit.text(), self.password_edit.text()) self.status.setText(result) def save_infomation(self): if self.username_edit.text() and self.password_edit.text(): try: selected = self.dataView.selectedIndexes()[0].row() self.modifyItem(selected) except IndexError: self.addItem(self.username_edit.text(), self.password_edit.text()) def test_network(self): result = test_public() self.status.setText(result) def set_text(self, event=None): try: self.username_edit.setText( self.dataView.selectedIndexes()[0].data()) self.password_edit.setText( self.dataView.selectedIndexes()[1].data()) except IndexError: pass def set_focus(self, event): index = self.dataView.indexAt(event.pos()) if not index.isValid(): self.dataView.clearSelection() else: self.dataView.setCurrentIndex(index) def readItem(self, filename): with open(filename, 'r') as f: for line in f.readlines(): self.addItem(*(line.split())) self.dataView.setCurrentIndex(self.dataView.indexAt(QPoint(1, 1))) self.set_text() def addItem(self, username, password): self.model.insertRow(0) self.model.setData(self.model.index(0, self.Id), username) self.model.setData(self.model.index(0, self.Password), password) self.save_to_file() def modifyItem(self, row): self.model.setData(self.model.index(row, self.Id), self.username_edit.text()) self.model.setData(self.model.index(row, self.Password), self.password_edit.text()) self.save_to_file() def removeItem(self): try: self.model.removeRow(self.dataView.selectedIndexes()[0].row()) self.save_to_file() except IndexError: pass def save_to_file(self): with open(self.CONFIG_FILE, 'w') as f: for x in range(self.model.rowCount()): for y in range(self.model.columnCount()): f.write(self.model.data(self.model.index(x, y)) + " ") f.write("\n") def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
class DisplaySongs(QWidget): def __init__(self): super().__init__() self.initializeUI() self.pb_search.clicked.connect(self.pb_search_clicked) self.pb_reload.clicked.connect(self.pb_reload_clicked) self.table_view.clicked.connect(self.select_song) def initializeUI(self): """ Initialize the window and display its contents to the screen. """ self.setWindowIcon(QIcon('icon.ico')) self.setGeometry(100, 100, 1200, 800) self.setWindowTitle('Songer-book') self.table_view = QTableView() self.table_view.setAlternatingRowColors(True) self.table_view.setSelectionMode(1) self.table_view.setSelectionBehavior(1) self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_view.horizontalHeader().setSectionResizeMode(1) self.setupModelView() self.le_search = QLineEdit() self.le_search.setPlaceholderText('Ведите название песни') self.pb_search = QPushButton('Найти') self.pb_reload = QPushButton('Загрузить заново') self.text_edit = QTextEdit() self.text_edit.setFont(QFont("Times", 17)) vbox1 = QVBoxLayout() hbox_mini = QHBoxLayout() hbox_mini.addWidget(self.le_search) hbox_mini.addWidget(self.pb_search) vbox1.addLayout(hbox_mini) vbox1.addWidget(self.table_view) vbox1.addWidget(self.pb_reload) vbox2 = QVBoxLayout() vbox2.addWidget(self.text_edit) hbox = QHBoxLayout() hbox.addLayout(vbox1) hbox.addLayout(vbox2) self.setLayout(hbox) self.show() def setupModelView(self): """ Set up standard item model and table view. """ self.model = QStandardItemModel() self.table_view.setModel(self.model) self.model.setRowCount(0) self.model.setColumnCount(2) self.loadDataFromDB() def loadDataFromDB(self, text=None): headers = ['Название композиции', 'Исполнитель(Автор)'] self.model.clear() self.model.setHorizontalHeaderLabels(headers) if text: data = get_data(text) else: data = get_data() for i, row in enumerate(data): items = [QStandardItem(item) for item in row[1:3]] self.model.insertRow(i, items) self.table_view.resizeColumnsToContents() self.table_view.resizeRowsToContents() def pb_search_clicked(self): text = self.le_search.text() self.loadDataFromDB(text) def pb_reload_clicked(self): self.le_search.clear() self.loadDataFromDB() def select_song(self): indexes = self.table_view.selectedIndexes() if indexes: index = indexes[0] title = self.table_view.model().data(index, Qt.DisplayRole) data = get_data(title)[0] self.text_edit.setText(data[3])
class GtoQgisSettingsDialog(QDialog): def __init__(self, gtomain, parent=None): super(GtoQgisSettingsDialog, self).__init__(parent) # gto self.gtomain = gtomain self.info = self.gtomain.info self.helper = self.gtomain.helper self.debug = self.gtomain.debug self.iface = self.gtomain.iface try: # references self.undoList = [] self.setWindowTitle('QGIS settings') self.setSizeGripEnabled(True) self.model = QStandardItemModel(self) self.model.setColumnCount(2) self.model.setHeaderData(0, Qt.Horizontal, "key") self.model.setHeaderData(1, Qt.Horizontal, "value") s = QSettings() for key in s.allKeys(): val = s.value(key) items = [] itKey = QStandardItem(key) itKey.setEditable(False) items.append(itKey) try: items.append(QStandardItem(val)) self.model.appendRow(items) except Exception as e: pass # if self.debug: self.info.err(e) self._proxy = MyFilter(self) self._proxy.setSourceModel(self.model) self.model.itemChanged.connect(self.dataChanged) # QstandardItem # create gui self.tableview = QTableView() self.tableview.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.tableview.horizontalHeader().setSectionsMovable(False) self.tableview.setSelectionBehavior( QAbstractItemView.SelectRows) # SelectItems self.tableview.setSelectionMode(QAbstractItemView.SingleSelection) self.tableview.setModel(self._proxy) self.search = QLineEdit() self.search.textChanged.connect(self.on_text_changed) self.btnDelete = QPushButton('Delete') self.btnDelete.clicked.connect(self.delete) self.btnAddRandowKey = QPushButton('add key') self.btnAddRandowKey.clicked.connect(self.addRandomKey) self.btnAddRandowKey.setHidden(not self.debug) # self.btnDelete.setEnabled(self.debug) self.btnUndo = QPushButton("Undo") self.btnUndo.setEnabled(False) self.btnUndo.clicked.connect(self.undo) self.btnCopy = QPushButton('Copy') self.btnCopy.clicked.connect(self.copy) self.chkPureJson = QCheckBox('Pure json') # layout search laySearch = QHBoxLayout() laySearch.addWidget(QLabel('Suche:')) laySearch.addWidget(self.search) # layout buttons layBtns = QHBoxLayout() layBtns.addWidget(self.btnAddRandowKey) layBtns.addWidget(self.btnDelete) layBtns.addWidget(self.btnUndo) hspacer = QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum) layBtns.addItem(hspacer) layBtns.addWidget(self.btnCopy) layBtns.addWidget(self.chkPureJson) # layout dialog self.layout = QVBoxLayout(self.iface.mainWindow()) self.layout.addLayout(laySearch) self.layout.addWidget(self.tableview) self.layout.addLayout(layBtns) self.setLayout(self.layout) self.resize(640, 480) self.tableview.sortByColumn(0, Qt.AscendingOrder) self.tableview.setSortingEnabled(True) self.tableview.selectRow(0) except Exception as e: self.info.err(e) def addRandomKey(self): try: if self.debug: val = str(random.random() * 100) key = val[0:1] + "/" + val[3:5] self.setQvalue(key, float(val)) items = [] it = QStandardItem(key) it.setEditable(False) items.append(it) items.append(QStandardItem(val)) self.model.appendRow(items) except Exception as e: self.info.err(e) def copy(self): try: index = self.tableview.currentIndex() key = self._proxy.index(index.row(), 0).data(0) val = self._proxy.index(index.row(), 1).data(0) s = QSettings() val = s.value(key) if self.debug: self.info.log("copy key:", key) if self.debug: self.info.log("copy val", val) if self.debug: self.info.log("copy Qval", val) if self.chkPureJson.isChecked(): val = json.dumps(val, ensure_ascii=False) else: val = self.getValue(val) text = '"{0}":{1},\n'.format(key, val) if self.debug: self.info.log("copy:", text) self.helper.copyToClipboard(text) except Exception as e: self.info.err(e) def getValue(self, val): try: # readable json expression: true instead of "true" or 9.99 instead of "9.99" if val is not None: try: # bool :S if val == "true": return json.dumps(True, ensure_ascii=False) if val == "false": return json.dumps(False, ensure_ascii=False) if val.lower() == "true": return json.dumps(True, ensure_ascii=False) if val.lower() == "false": return json.dumps(False, ensure_ascii=False) except: pass try: # integer return int(val) except: pass try: # float return float(val) except: pass if val is not None: if isinstance(val, str): return json.dumps(val, ensure_ascii=False) if not (isinstance(val, list) or isinstance(val, dict)): val = [val] lst = json.dumps(val, ensure_ascii=False) val = lst[1:-1] if val == "": val = None return json.dumps(val, ensure_ascii=False) except Exception as e: if self.debug: self.info.err(e) return val def delete(self, *args): try: index = self._proxy.mapSelectionToSource( self.tableview.selectionModel().selection()).indexes()[0] row = index.row() items = self.model.takeRow(row) # QList<QStandardItem> key = items[0].data(0) val = items[1].data(0) if self.debug: self.info.log("delete key:", key) if self.debug: self.info.log("delte val", val) s = QSettings() s.remove(key) self.undoList.append((index, items)) self.btnUndo.setEnabled(True) except Exception as e: self.info.err(e) def undo(self): try: if len(self.undoList) > 0: self.undoList.reverse() index, items = self.undoList[0] key = items[0].data(0) val = items[1].data(0) if self.debug: self.info.log("undo key:", key) if self.debug: self.info.log("undo val", val) self.setQvalue(key, val) self.model.insertRow(index.row(), items) tabindex = self._proxy.mapFromSource(index) self.tableview.selectRow(tabindex.row()) del self.undoList[0] self.undoList.reverse() if len(self.undoList) == 0: self.btnUndo.setEnabled(False) except Exception as e: self.info.err(e) def dataChanged(self, item): try: val = item.data(0) key = self.model.item(item.row(), 0).data(0) if self.debug: self.info.log("datachanged key:", key) if self.debug: self.info.log("datachanged val", val) self.setQvalue(key, val) except Exception as e: self.info.err(e) def setQvalue(self, key, val): try: s = QSettings() s.setValue(key, val) except Exception as e: self.info.err(e) @pyqtSlot(str) def on_text_changed(self, text): try: regExp = QRegExp(text, Qt.CaseInsensitive, QRegExp.Wildcard) self._proxy.setFilterRegExp(regExp) except Exception as e: self.info.err(e)
class FriendVeiw(Ui_Form): #分组信息存储 grouplist = [] #用户信息存储 userlist = [] def __init__(self, parent=None): super(FriendVeiw, self).__init__(parent) print('sss') self.setupUi() # self.show() self.Ui_init() def Ui_init(self): # 设置好友图标大小等 # print('3', self, '4', self.form) self.treeWidget.setColumnCount(1) self.treeWidget.setColumnWidth(0, 50) self.treeWidget.setHeaderLabels(['好友']) self.treeWidget.setIconSize(QSize(50, 50)) # 搜索时自动填充,创建一个缓存空间, 0行1列 self.add_model = QStandardItemModel(0, 1, self) add_completer = QCompleter(self.add_model, self) self.lineEdit.setCompleter(add_completer) add_completer.activated[str].connect(self.onUsernameChoosed) self.treeWidget.setSelectionMode(QAbstractItemView.MultiSelection) # print('t1') self.treeWidget.itemSelectionChanged.connect(self.getListitems) self.treeWidget.itemDoubleClicked.connect(self.open_chatview) # print('t2') # self.treeWidget.currentItemChanged.connect(self.restatistic) # self.treeWidget.itemClicked.connect(self.isclick) # 样式的设置 # with codecs.open('./qss/treeWidget.qss', 'r', 'utf-8') as f: # style = f.read() # print(style) # self.treeWidget.setStyleSheet(style) # 添加好友分组 root = self.createGroup('我的好友') # root1 = self.createGroup('我的群组') root.setExpanded(True) # root1.setExpanded(True) # 创建好友分组 def createGroup(self, groupname): onlinenum = 0 group = QTreeWidgetItem(self.treeWidget) groupdic = { 'group': group, 'groupname': groupname, 'childcount': 0, 'childstatus': 0 } # 给分组设置小图标 icon = self.searchicon(groupname) group.setIcon(0, icon) # # # with codecs.open('friend_info', 'r', 'utf-8') as f: # # fre_info = f.read() # # print(fre_info.split('\r\n')) fre_info = [['小李', '1001', '0', '../images/user/0.jpg'], ['小强', '1002', '1', '../images/user/0.jpg'], ['小明', '1003', '1', '../images/user/0.jpg']] for item in fre_info: child = QTreeWidgetItem() uname = item[0] chatID = item[1] status = item[2] icon_path = QIcon(item[3]) name = uname + '(%s)' % chatID # name, chatID, icon_path, font, status = self.createUser(item) font = QFont() font.setPointSize(9) userdic = { 'user': child, 'username': name, 'userID': chatID, 'status': status } self.userlist.append(userdic) child.setFont(0, font) child.setIcon(0, icon_path) # 离线、在线判断 onlinenum, name = self.judge_online(status, onlinenum, name, child) group.addChild(child) # 判断在线、总人数 childnum = group.childCount() print('childnum:', childnum, 'online:', onlinenum) off_line_num = childnum - onlinenum groupdic['childcount'] = childnum groupdic['childstatus'] = onlinenum groupname += ' ' + str(onlinenum) + '/' + str(childnum) group.setText(0, groupname) self.grouplist.append(groupdic) # print('grouplist:', self.grouplist) return group # 在线、离线判断 def judge_online(self, status, onlinenum, name, child): if status == '1': onlinenum += 1 name += ' 在线' child.setText(0, name) else: name += ' 离线' child.setText(0, name) return onlinenum, name # 设置菜单 def contextMenuEvent(self, event): hititem = self.treeWidget.currentItem() print('event', event, 'hititem', hititem) if hititem: # 当root是 None 时,此时节点在分组上 root = hititem.parent() if root is None: pgroupmenu = QMenu(self) pAddgroupAct = QAction('添加分组', self.treeWidget) pRenameAct = QAction('重命名', self.treeWidget) pDeleteAct = QAction('删除该组', self.treeWidget) pgroupmenu.addAction(pAddgroupAct) pgroupmenu.addAction(pRenameAct) pgroupmenu.addAction(pDeleteAct) pAddgroupAct.triggered.connect(self.addgroup) pRenameAct.triggered.connect(self.renamegroup) if self.treeWidget.itemAbove(hititem) is None: pDeleteAct.setEnabled(False) else: pDeleteAct.triggered.connect(self.deletegroup) pgroupmenu.popup(self.mapToGlobal(event.pos())) # 此时节点在联系人上 elif root.childCount() > 0: pItemmenu = QMenu(self) pDeleteItemAct = QAction('删除联系人', pItemmenu) pRenameItemAct = QAction('添加备注', pItemmenu) pItemmenu.addAction(pDeleteItemAct) pItemmenu.addAction(pRenameItemAct) pDeleteItemAct.triggered.connect(self.delete) pRenameItemAct.triggered.connect(self.renameItem) print('font', hititem.text(0)) # 左键点击事件 # self.treeWidget.itemDoubleClicked(hititem).connect(self.click_event) # 当联系人大于 1时,可以转移 if len(self.grouplist) > 1: pSubMenu = QMenu('转移联系人至', pItemmenu) pItemmenu.addMenu(pSubMenu) for item_dic in self.grouplist: if item_dic['group'] is not root: pMoveAct = QAction(item_dic['groupname'], pItemmenu) pSubMenu.addAction(pMoveAct) pMoveAct.triggered.connect(self.moveItem) pItemmenu.popup(self.mapToGlobal(event.pos())) # 添加分组 def addgroup(self): gname, ok = QInputDialog.getText(self, '提示信息', '请输入分组名称') if ok: if len(gname) == 0: QMessageBox.information(self, '提示', '分组名称不能为空哦') else: self.createGroup(gname) # 重命名 def renamegroup(self): hitgroup = self.treeWidget.currentItem() gnewname, ok = QInputDialog.getText(self, '提示信息', '请输入分组的新名称') if ok: if len(gnewname) == 0: QMessageBox.information(self, '提示', '分组名称不能为空哦') else: hitgroup.setText(0, gnewname) newicon = self.searchicon(hitgroup.text(0)) hitgroup.setIcon(0, newicon) gindex = self.searchgroup(hitgroup) self.grouplist[gindex]['groupname'] = gnewname self.treeWidget.setCurrentItem(hitgroup.child(0)) # 给联系人添加备注 def renameItem(self): hituser = self.treeWidget.currentItem() uindex = self.searchuser(hituser) unewname, ok = QInputDialog.getText(self, '提示信息', '请输入备注名称') if ok: if len(unewname) == 0: QMessageBox.information(self, '提示', '备注名称不能为空哦') else: hituser.setText(0, unewname) self.userslist[uindex]['username'] = unewname # 删除分组 def deletegroup(self): hitgroup = self.treeWidget.currentItem() gindex = self.searchgroup(hitgroup) reply = QMessageBox.question(self, '警告', '确定要删除这个分组及其联系人吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.treeWidget.takeTopLevelItem(gindex) del self.grouplist[gindex] # 移动联系人 def moveItem(self): movelist = self.getListitems(self.menuflag) togroupname = self.sender().text() mindex = self.searchgroup(togroupname) togroup = self.grouplist[mindex]['group'] self.deleteItems(movelist, flag=0) self.add(togroup, movelist) self.tmpuseritem.clear() def delete(self): delitems = self.getListitems(self.menuflag) self.deleteItems(delitems) self.tmpuseritem.clear() def deleteItems(self, items, flag=1): for delitem in items: delitem.setData(0, Qt.CheckStateRole, QVariant()) #取消删除item的复选框 pindex = delitem.parent().indexOfChild(delitem) dindex = self.searchuser(delitem) ishide = self.userslist[dindex]['ishide'] if flag == 1: del self.userslist[dindex] fathergroup = delitem.parent() findex = self.searchgroup(fathergroup) if ishide == 1: self.grouplist[findex]['childishide'] -= 1 self.grouplist[findex]['childcount'] -= 1 else: self.grouplist[findex]['childcount'] -= 1 delitem.parent().takeChild(pindex) def add(self, group, items): gindex = self.searchgroup(group) for item in items: aindex = self.searchuser(item) ishide = self.userslist[aindex]['ishide'] if ishide == 1: self.grouplist[gindex]['childishide'] += 1 self.grouplist[gindex]['childcount'] += 1 else: self.grouplist[gindex]['childcount'] += 1 group.addChild(item) self.treeWidget.setCurrentItem(item) def Batchoperation(self): self.menuflag *= -1 group = self.getListitems()[0].parent() childnum = group.childCount() for c in range(childnum): child = group.child(c) child.setCheckState(0, Qt.Unchecked) def CancelBatchoperation(self): self.menuflag *= -1 group = self.getListitems()[0].parent() childnum = group.childCount() for c in range(childnum): child = group.child(c) child.setData(0, Qt.CheckStateRole, QVariant()) def isclick(self, item): if item.checkState(0) == Qt.Checked: if self.tmpuseritem.count(item) == 0: self.tmpuseritem.append(item) else: if len(self.tmpuseritem) > 0: if self.tmpuseritem.count(item) != 0: i = self.tmpuseritem.index(item) del self.tmpuseritem[i] # 查找分组 def searchgroup(self, hitgroup): if isinstance(hitgroup, str): for i, g in enumerate(self.grouplist): if g['groupname'] == hitgroup: return i else: for i, g in enumerate(self.grouplist): if g['group'] == hitgroup: return i def searchuser(self, hituser): if isinstance(hituser, str): for i, u in enumerate(self.userlist): if u['userID'] == hituser: return i else: for i, u in enumerate(self.userslist): if u['user'] == hituser: return i def searchicon(self, gpname2): if gpname2.find('好友') >= 0: return QIcon('../iamges/list_images/buddy.ico') elif gpname2.find('同事') >= 0: return QIcon('../images/list_images/partner.ico') elif gpname2.find('黑名单') >= 0: return QIcon('../images/list_images/blacklist.ico') else: return QIcon('../images/list_images/buddy_default.ico') # 返回当前对象 def getListitems(self, flag=1): if flag > 0: return self.treeWidget.selectedItems() def restatistic(self, item, preitem): if item: fathergroup = item.parent() if fathergroup: self.restatistic_op(fathergroup) else: self.restatistic_op(item) elif preitem.parent().childCount() == 1: lastgroupname = preitem.parent().text(0).split()[0] + ' 0/0' preitem.parent().setText(0, lastgroupname) self.menuflag = 1 def restatistic_op(self, itemorgroup): gindex = self.searchgroup(itemorgroup) totalcount = self.grouplist[gindex]['childcount'] hidecount = self.grouplist[gindex]['childishide'] fathergroupname = self.grouplist[gindex]['groupname'] fathergroupname += ' ' + str(totalcount - hidecount) + '/' + str(totalcount) itemorgroup.setText(0, fathergroupname) def open_chatview(self): t = Thread() print('2222') user_id, user_name = self.handle_info() try: # app = QApplication(sys.argv) self.hide() ch = ChatForm(user_id, user_name) ch.show() ch.exec_() # sys.exit(app.exec_()) except Exception as e: print(e) t.start() t.join() # 双击时获取好友信息 def handle_info(self): hititem = self.treeWidget.currentItem() text = hititem.text(0) partern = '\d+' user_id = re.findall(partern, text) partern1 = '^\w+' user_name = re.findall(partern1, text) print('11', user_id[0], user_name[0]) return user_id[0], user_name[0] # 添加好友 @pyqtSlot() def on_bt_adduser_clicked(self): addUser = AddFriend() for gro in self.grouplist: addUser.comboBox.addItem(gro['groupname']) r = addUser.exec_() if r > 0: newItem = QTreeWidgetItem() newId = addUser.lineEdit_add.text() print('newId', newId) # 设置一个接口 获取 id 对应的信息 newUser = ['小李', '1006', '1', '../images/user/7.jpg'] newName = newUser[0] newStatus = newUser[2] newPath = QIcon(newUser[3]) name = newName + '(%s)' % newId font = QFont() font.setPointSize(9) userdic = { 'user': newItem, 'username': name, 'userID': newId, 'status': newStatus } self.userlist.append(userdic) newItem.setFont(0, font) newItem.setIcon(0, newPath) newItem.setText(0, name) comboInfo = addUser.comboBox.currentText() conboIndex = self.searchgroup(comboInfo) group = self.grouplist[conboIndex]['group'] self.grouplist[conboIndex]['childcount'] += 1 group.addChild(newItem) self.treeWidget.setCurrentItem(newItem) # 获取lineEdit的输入信息 def onUsernameChoosed(self, name): self.lineEdit.setText(name) # 查找好友 @pyqtSlot() def on_bt_search_clicked(self): userId = self.lineEdit.text() if len(userId) > 0: user_index = self.searchuser(userId) print('user', user_index) userItem = self.userlist[user_index]['user'] self.treeWidget.setCurrentItem(userItem) @pyqtSlot(str) def on_lineEdit_textChanged(self, text): unameList = [] for i in self.userlist: userName = i['username'] if userName.find(text) > 0: unameList.append(userName) self.add_model.removeRows(0, self.add_model.rowCount()) for n in range(0, len(unameList)): self.add_model.insertRow(0) self.add_model.setData(self.add_model.index(0, 0), unameList[n])
class WelcomeDialog(QDialog): onSessionSelected = pyqtSignal(str, name='onSessionSelected') onSessionRestore = pyqtSignal(dict, name='onSessionRestore') onUpdateComplete = pyqtSignal(name='onUpdateComplete') onIsNewerVersion = pyqtSignal(name='onIsNewerVersion') def __init__(self, parent=None): super(WelcomeDialog, self).__init__(parent=parent) self._prefs = parent.prefs self._sub_titles = [ ['duck', 'dumb', 'doctor', 'dutch', 'dark', 'dirty'], ['warriors', 'wardrobes', 'waffles', 'wishes'], ['are', 'aren\'t', 'ain\'t', 'appears to be'], ['rich', 'real', 'riffle', 'retarded', 'rock'], ['as f**k', 'fancy', 'f****d', 'front-ended', 'falafel', 'french fries'], ] self._recent_list_model = QStandardItemModel(0, 6) self._recent_list_model.setHeaderData(0, Qt.Horizontal, 'Path') self._recent_list_model.setHeaderData(1, Qt.Horizontal, 'Session') self._recent_list_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._recent_list_model.setHeaderData(2, Qt.Horizontal, 'Hooks') self._recent_list_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._recent_list_model.setHeaderData(3, Qt.Horizontal, 'Watchers') self._recent_list_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._recent_list_model.setHeaderData(4, Qt.Horizontal, 'OnLoads') self._recent_list_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._recent_list_model.setHeaderData(5, Qt.Horizontal, 'Bookmarks') self._recent_list_model.setHeaderData(5, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) #self._recent_list_model.setHeaderData(6, Qt.Horizontal, 'Custom script') #self._recent_list_model.setHeaderData(6, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._recent_list = DwarfListView(self) self._recent_list.setModel(self._recent_list_model) self._recent_list.header().setSectionResizeMode(0, QHeaderView.ResizeToContents | QHeaderView.Interactive) self._recent_list.header().setSectionResizeMode(1, QHeaderView.Stretch) self._recent_list.header().setSectionResizeMode(2, QHeaderView.Stretch) self._recent_list.header().setSectionResizeMode(3, QHeaderView.Stretch) self._recent_list.header().setSectionResizeMode(4, QHeaderView.Stretch) self._recent_list.header().setSectionResizeMode(5, QHeaderView.Stretch) #self._recent_list.header().setSectionResizeMode(6, QHeaderView.Stretch) self._recent_list.setContextMenuPolicy(Qt.CustomContextMenu) self._recent_list.customContextMenuRequested.connect(self._on_recent_sessions_context_menu) self._recent_list.doubleClicked.connect(self._on_recent_session_double_click) # setup size and remove/disable titlebuttons self.desktop_geom = qApp.desktop().availableGeometry() self.setFixedSize(self.desktop_geom.width() * .45, self.desktop_geom.height() * .38) self.setGeometry(QStyle.alignedRect(Qt.LeftToRight, Qt.AlignCenter, self.size(), qApp.desktop().availableGeometry())) self.setSizeGripEnabled(False) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.setWindowFlag(Qt.WindowContextHelpButtonHint, False) self.setWindowFlag(Qt.WindowCloseButtonHint, True) self.setModal(True) # setup ui elements self.setup_ui() self.update_commits_thread = DwarfCommitsThread(parent) self.update_commits_thread.on_update_available.connect(self._on_dwarf_isupdate) self.update_commits_thread.start() # center self.setGeometry( QStyle.alignedRect(Qt.LeftToRight, Qt.AlignCenter, self.size(), qApp.desktop().availableGeometry())) def setup_ui(self): """ Setup Ui """ main_wrap = QVBoxLayout() main_wrap.setContentsMargins(0, 0, 0, 0) # updatebar on top self.update_bar = UpdateBar(self) self.update_bar.onUpdateNowClicked.connect(self._update_dwarf) self.update_bar.setVisible(False) main_wrap.addWidget(self.update_bar) # main content h_box = QHBoxLayout() h_box.setContentsMargins(15, 15, 15, 15) wrapper = QVBoxLayout() # wrapper.setGeometry(QRect(0, 0, 400, 200)) head = QHBoxLayout() head.setContentsMargins(0, 10, 0, 10) # dwarf icon icon = QLabel() icon.setContentsMargins(40, 0, 0, 0) dwarf_logo = QPixmap(utils.resource_path('assets/dwarf.svg')) icon.setPixmap(dwarf_logo) head.addWidget(icon) # main title v_box = QVBoxLayout() title = QLabel('Dwarf') title.setContentsMargins(0, 0, 50, 0) title.setFont(QFont('Anton', 90, QFont.Bold)) title.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) title.setFixedHeight(self.height() * .35) title.setAlignment(Qt.AlignCenter) v_box.addWidget(title) sub_title_text = (self._pick_random_word(0) + ' ' + self._pick_random_word(1) + ' ' + self._pick_random_word(2) + ' ' + self._pick_random_word(3) + ' ' + self._pick_random_word(4)) sub_title_text = sub_title_text[:1].upper() + sub_title_text[1:] sub_title = QLabel(sub_title_text) sub_title.setFont(QFont('OpenSans', 14, QFont.Bold)) sub_title.setFixedHeight(title.height() * .25) sub_title.setAlignment(Qt.AlignCenter) sub_title.setContentsMargins(0, 0, 50, 0) sub_title.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) v_box.addWidget(sub_title) head.addLayout(v_box) wrapper.addLayout(head) recent = QLabel('Last saved Sessions') font = recent.font() font.setBold(True) #font.setPointSize(10) recent.setFont(font) wrapper.addWidget(recent) wrapper.addWidget(self._recent_list) h_box.addLayout(wrapper, stretch=False) buttonSpacer = QSpacerItem(15, 100, QSizePolicy.Fixed, QSizePolicy.Minimum) h_box.addItem(buttonSpacer) wrapper = QVBoxLayout() btn = QPushButton() ico = QIcon(QPixmap(utils.resource_path('assets/android.svg'))) btn.setIconSize(QSize(75, 75)) btn.setIcon(ico) btn.setToolTip('New Android Session') btn.clicked.connect(self._on_android_button) wrapper.addWidget(btn) btn = QPushButton() ico = QIcon(QPixmap(utils.resource_path('assets/apple.svg'))) btn.setIconSize(QSize(75, 75)) btn.setIcon(ico) btn.setToolTip('New iOS Session') btn.clicked.connect(self._on_ios_button) wrapper.addWidget(btn) btn = QPushButton() ico = QIcon(QPixmap(utils.resource_path('assets/local.svg'))) btn.setIconSize(QSize(75, 75)) btn.setIcon(ico) btn.setToolTip('New Local Session') btn.clicked.connect(self._on_local_button) wrapper.addWidget(btn) btn = QPushButton() ico = QIcon(QPixmap(utils.resource_path('assets/remote.svg'))) btn.setIconSize(QSize(75, 75)) btn.setIcon(ico) btn.setToolTip('New Remote Session') btn.clicked.connect(self._on_remote_button) wrapper.addWidget(btn) session_history = self._prefs.get(prefs.RECENT_SESSIONS, default=[]) invalid_session_files = [] for recent_session_file in session_history: if os.path.exists(recent_session_file): with open(recent_session_file, 'r') as f: exported_session = json.load(f) hooks = '0' watchers = '0' on_loads = 0 bookmarks = '0' #have_user_script = False if 'hooks' in exported_session and exported_session['hooks'] is not None: hooks = str(len(exported_session['hooks'])) if 'watchers' in exported_session and exported_session['watchers'] is not None: watchers = str(len(exported_session['watchers'])) if 'nativeOnLoads' in exported_session and exported_session['nativeOnLoads'] is not None: on_loads += len(exported_session['nativeOnLoads']) if 'javaOnLoads' in exported_session and exported_session['javaOnLoads'] is not None: on_loads += len(exported_session['javaOnLoads']) if 'bookmarks' in exported_session and exported_session['bookmarks'] is not None: bookmarks = str(len(exported_session['bookmarks'])) if 'user_script' in exported_session and exported_session['user_script']: have_user_script = exported_session['user_script'] != '' #user_script_item = QStandardItem() #if have_user_script: #user_script_item.setIcon(self._dot_icon) on_loads = str(on_loads) recent_session_file_item = QStandardItem(recent_session_file) recent_session_file_item.setData(exported_session, Qt.UserRole + 2) item_1 = QStandardItem(exported_session['session']) item_1.setTextAlignment(Qt.AlignCenter) item_2 = QStandardItem(hooks) item_2.setTextAlignment(Qt.AlignCenter) item_3 = QStandardItem(watchers) item_3.setTextAlignment(Qt.AlignCenter) item_4 = QStandardItem(on_loads) item_4.setTextAlignment(Qt.AlignCenter) item_5 = QStandardItem(bookmarks) item_5.setTextAlignment(Qt.AlignCenter) #item_6 = QStandardItem(user_script_item) #item_6.setTextAlignment(Qt.AlignCenter) self._recent_list_model.insertRow(self._recent_list_model.rowCount(), [ recent_session_file_item, item_1, item_2, item_3, item_4, item_5 ]) else: invalid_session_files.append(recent_session_file) for invalid in invalid_session_files: session_history.pop(session_history.index(invalid)) self._prefs.put(prefs.RECENT_SESSIONS, session_history) h_box.addLayout(wrapper, stretch=False) main_wrap.addLayout(h_box) self.setLayout(main_wrap) def _on_dwarf_isupdate(self): self.update_bar.setVisible(True) self.onIsNewerVersion.emit() def _update_dwarf(self): self._update_thread = DwarfUpdateThread(self) self._update_thread.on_finished.connect(self._update_finished) if not self._update_thread.isRunning(): self._update_thread.start() def _update_finished(self): self.onUpdateComplete.emit() def _on_android_button(self): self.onSessionSelected.emit('Android') self.close() def _on_local_button(self): self.onSessionSelected.emit('Local') self.close() def _on_ios_button(self): self.onSessionSelected.emit('Ios') self.close() def _on_remote_button(self): self.onSessionSelected.emit('Remote') self.close() def _pick_random_word(self, arr): return self._sub_titles[arr][random.randint(0, len(self._sub_titles[arr]) - 1)] def _on_recent_sessions_context_menu(self, pos): index = self.list_view.indexAt(pos).row() glbl_pt = self.list_view.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: context_menu.addAction( 'Delete recent session', lambda: self._remove_recent_sessions( self._recent_list_model.item(index, 0).text())) context_menu.exec_(glbl_pt) def _remove_recent_session(self, session_file): if os.path.exists(session_file): os.remove(session_file) session_history = self._prefs.get(prefs.RECENT_SESSIONS, default=[]) if session_file in session_history: session_history.pop(session_history.index(session_file)) self._prefs.put(prefs.RECENT_SESSIONS, session_history) def _on_recent_session_double_click(self, model_index): row = self._recent_list_model.itemFromIndex(model_index).row() recent_session_file = self._recent_list_model.item(row, 0) recent_session_data = recent_session_file.data(Qt.UserRole + 2) self.onSessionRestore.emit(recent_session_data)
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui=Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.setCentralWidget(self.ui.splitter) self.__buildStatusBar() self.COL_COUNT=6 #常数,列数=6 self.itemModel = QStandardItemModel(5,self.COL_COUNT,self) # 数据模型,10行6列 ## headerList=["测深(m)","垂深(m)","方位(°)","总位移(m)","固井质量","测井取样"] ## self.itemModel.setHorizontalHeaderLabels(headerList) #设置表头文字 self.selectionModel = QItemSelectionModel(self.itemModel) #Item选择模型 self.selectionModel.currentChanged.connect(self.do_currentChanged) self.__lastColumnFlags=(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) self.__lastColumnTitle="测井取样" #为tableView设置数据模型 self.ui.tableView.setModel(self.itemModel) #设置数据模型 self.ui.tableView.setSelectionModel(self.selectionModel) #设置选择模型 oneOrMore=QAbstractItemView.ExtendedSelection self.ui.tableView.setSelectionMode(oneOrMore) #可多选 itemOrRow=QAbstractItemView.SelectItems self.ui.tableView.setSelectionBehavior(itemOrRow) #单元格选择 self.ui.tableView.verticalHeader().setDefaultSectionSize(22)#缺省行高 self.ui.tableView.setEnabled(False) #先禁用tableView ## self.__resetTable(5) #创建自定义代理组件并设置 self.spinCeShen=QmyFloatSpinDelegate(0,10000, 0,self) #用于 测深 self.spinLength=QmyFloatSpinDelegate(0,6000, 2,self) #垂深,总位移 self.spinDegree=QmyFloatSpinDelegate(0,360, 1,self) #用于 方位 self.ui.tableView.setItemDelegateForColumn(0,self.spinCeShen) #测深 self.ui.tableView.setItemDelegateForColumn(1,self.spinLength) #垂深 self.ui.tableView.setItemDelegateForColumn(3,self.spinLength) #总位移 self.ui.tableView.setItemDelegateForColumn(2,self.spinDegree) #方位角 qualities=["优","良","合格","不合格"] self.comboDelegate=QmyComboBoxDelegate(self) self.comboDelegate.setItems(qualities,False) #不可编辑 self.ui.tableView.setItemDelegateForColumn(4,self.comboDelegate) #固井质量 ## ==============自定义功能函数============ def __buildStatusBar(self): ##构建状态栏 self.LabCellPos = QLabel("当前单元格:",self) self.LabCellPos.setMinimumWidth(180) self.ui.statusBar.addWidget(self.LabCellPos) self.LabCellText = QLabel("单元格内容:",self) self.LabCellText.setMinimumWidth(150) self.ui.statusBar.addWidget(self.LabCellText) self.LabCurFile = QLabel("当前文件:",self) self.ui.statusBar.addPermanentWidget(self.LabCurFile) ## def __resetTable(self,tableRowCount): #复位数据表,必须为数值设置0,否则代理组件出错 ## self.itemModel.removeRows(0,self.itemModel.rowCount()) #删除所有行 ## self.itemModel.setRowCount(tableRowCount) #设置新的行数 ## ## for i in range(tableRowCount): #设置最后一列 ## for j in range(self.COL_COUNT-1): ## index=self.itemModel.index(i,j) #获取模型索引 ## item=self.itemModel.itemFromIndex(index) #获取item ## item.setData(0,Qt.DisplayRole) #数值必须初始化为0 ## item.setTextAlignment(Qt.AlignHCenter) ## ## index=self.itemModel.index(i,self.COL_COUNT-1) #获取模型索引 ## item=self.itemModel.itemFromIndex(index) #获取item ## item.setCheckable(True) ## item.setData(self.__lastColumnTitle,Qt.DisplayRole) ## item.setEditable(False) #不可编辑 def __iniModelFromStringList(self,allLines): ##从字符串列表构建模型 rowCnt=len(allLines) #文本行数,第1行是标题 self.itemModel.setRowCount(rowCnt-1) #实际数据行数 headerText=allLines[0].strip() #第1行是表头,去掉末尾的换行符 "\n" headerList=headerText.split("\t") self.itemModel.setHorizontalHeaderLabels(headerList) self.__lastColumnTitle=headerList[len(headerList)-1] # 最后一列表头的标题,即“测井取样” lastColNo=self.COL_COUNT-1 #最后一列的列号 for i in range(rowCnt-1): lineText=allLines[i+1].strip() #一行的文字,\t分隔 strList=lineText.split("\t") for j in range(self.COL_COUNT-1): #不含最后一列 item=QStandardItem(strList[j]) self.itemModel.setItem(i,j,item) item=QStandardItem(self.__lastColumnTitle) #最后一列 item.setFlags(self.__lastColumnFlags) item.setCheckable(True) if (strList[lastColNo]=="0"): item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Checked) self.itemModel.setItem(i,lastColNo,item) #设置最后一列的item def __setCellAlignment(self, align=Qt.AlignHCenter): if (not self.selectionModel.hasSelection()): #没有选择的项 return selectedIndex=self.selectionModel.selectedIndexes() #列表类型 count=len(selectedIndex) for i in range(count): index=selectedIndex[i] #获取其中的一个模型索引 item=self.itemModel.itemFromIndex(index) #获取一个单元格的项数据对象 item.setTextAlignment(align) #设置文字对齐方式 ## ==========由connectSlotsByName() 自动连接的槽函数================== @pyqtSlot() ##“打开文件” def on_actOpen_triggered(self): curPath=os.getcwd() #获取当前路径 filename,flt=QFileDialog.getOpenFileName(self,"打开一个文件",curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename==""): return self.LabCurFile.setText("当前文件:"+filename) self.ui.plainTextEdit.clear() aFile=open(filename,'r') allLines=aFile.readlines() #读取所有行,list类型,每行末尾带有 \n ## for eachLine in aFile: #每次读取一行 ## self.ui.plainTextEdit.appendPlainText(eachLine) aFile.close() for strLine in allLines: self.ui.plainTextEdit.appendPlainText(strLine.strip()) self.__iniModelFromStringList(allLines) self.ui.actAppend.setEnabled(True) #更新Actions的enable属性 self.ui.actInsert.setEnabled(True) self.ui.actDelete.setEnabled(True) self.ui.actSave.setEnabled(True) self.ui.actModelData.setEnabled(True) self.ui.tableView.setEnabled(True) #启用tableView @pyqtSlot() ##保存文件 def on_actSave_triggered(self): curPath=os.getcwd() #获取当前路径 filename,flt=QFileDialog.getSaveFileName(self,"保存文件",curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename==""): return self.on_actModelData_triggered() #更新数据到plainTextEdit aFile=open(filename,'w') #以写方式打开 aFile.write(self.ui.plainTextEdit.toPlainText()) aFile.close() @pyqtSlot() def on_actAppend_triggered(self): #在最后添加一行 itemlist=[] # 列表 for i in range(self.COL_COUNT-1): item=QStandardItem("0") itemlist.append(item) item=QStandardItem(self.__lastColumnTitle) #最后一列 item.setCheckable(True) item.setFlags(self.__lastColumnFlags) itemlist.append(item) self.itemModel.appendRow(itemlist) curIndex=self.itemModel.index(self.itemModel.rowCount()-1,0) self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex,QItemSelectionModel.Select) @pyqtSlot() ##插入一行 def on_actInsert_triggered(self): itemlist=[] # 列表 for i in range(self.COL_COUNT-1): item=QStandardItem("0") itemlist.append(item) item=QStandardItem(self.__lastColumnTitle) #最后一列 item.setFlags(self.__lastColumnFlags) item.setCheckable(True) item.setCheckState(Qt.Checked) itemlist.append(item) curIndex=self.selectionModel.currentIndex(); #获取当前选中项的模型索引 self.itemModel.insertRow(curIndex.row(),itemlist); #在当前行的前面插入一行 self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex,QItemSelectionModel.Select) @pyqtSlot() ##删除当前行 def on_actDelete_triggered(self): curIndex=self.selectionModel.currentIndex()#获取当前选择单元格的模型索引 self.itemModel.removeRow(curIndex.row())# //删除当前行 @pyqtSlot() ##左对齐 def on_actAlignLeft_triggered(self): self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter) @pyqtSlot() ##中间对齐 def on_actAlignCenter_triggered(self): self.__setCellAlignment(Qt.AlignHCenter| Qt.AlignVCenter) @pyqtSlot() ##右对齐 def on_actAlignRight_triggered(self): self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter) @pyqtSlot(bool) ##字体Bold def on_actFontBold_triggered(self,checked): if (not self.selectionModel.hasSelection()): #没有选择的项 return selectedIndex=self.selectionModel.selectedIndexes() #列表类型 count=len(selectedIndex) for i in range(count): index=selectedIndex[i] #获取其中的一个模型索引 item=self.itemModel.itemFromIndex(index) #获取一个单元格的项数据对象 font=item.font() font.setBold(checked) item.setFont(font) @pyqtSlot() ##模型数据显示到plainTextEdit里 def on_actModelData_triggered(self): self.ui.plainTextEdit.clear() lineStr="" for i in range(self.itemModel.columnCount()-1): #表头 item=self.itemModel.horizontalHeaderItem(i) lineStr=lineStr+item.text()+"\t" item=self.itemModel.horizontalHeaderItem(self.COL_COUNT-1) #最后一列 lineStr=lineStr+item.text() self.ui.plainTextEdit.appendPlainText(lineStr) for i in range(self.itemModel.rowCount()): lineStr="" for j in range(self.itemModel.columnCount()-1): #不包括最后一列 item=self.itemModel.item(i,j) lineStr=lineStr+item.text()+"\t" item=self.itemModel.item(i,self.COL_COUNT-1) #最后一列 if (item.checkState()==Qt.Checked): lineStr=lineStr+"1" else: lineStr=lineStr+"0" self.ui.plainTextEdit.appendPlainText(lineStr) ## =============自定义槽函数=============================== def do_currentChanged(self,current,previous): if (current != None): #当前模型索引有效 self.LabCellPos.setText("当前单元格:%d行,%d列" %(current.row(),current.column())) #显示模型索引的行和列号 item=self.itemModel.itemFromIndex(current) #从模型索引获得Item self.LabCellText.setText("单元格内容:"+item.text()) #显示item的文字内容 font=item.font() #获取item的字体 self.ui.actFontBold.setChecked(font.bold()) #更新actFontBold的check状态
class QtWidgetRegistry(QObject, WidgetRegistry): """ A QObject wrapper for `WidgetRegistry` A QStandardItemModel instance containing the widgets in a tree (of depth 2). The items in a model can be quaries using standard roles (DisplayRole, BackgroundRole, DecorationRole ToolTipRole). They also have QtWidgetRegistry.CATEGORY_DESC_ROLE, QtWidgetRegistry.WIDGET_DESC_ROLE, which store Category/WidgetDescription respectfully. Furthermore QtWidgetRegistry.WIDGET_ACTION_ROLE stores an default QAction which can be used for widget creation action. """ CATEGORY_DESC_ROLE = Qt.UserRole + 1 """Category Description Role""" WIDGET_DESC_ROLE = Qt.UserRole + 2 """Widget Description Role""" WIDGET_ACTION_ROLE = Qt.UserRole + 3 """Widget Action Role""" BACKGROUND_ROLE = Qt.UserRole + 4 """Background color for widget/category in the canvas (different from Qt.BackgroundRole) """ category_added = Signal(str, CategoryDescription) """signal: category_added(name: str, desc: CategoryDescription) """ widget_added = Signal(str, str, WidgetDescription) """signal widget_added(category_name: str, widget_name: str, desc: WidgetDescription) """ reset = Signal() """signal: reset() """ def __init__(self, other_or_parent=None, parent=None): if isinstance(other_or_parent, QObject) and parent is None: parent, other_or_parent = other_or_parent, None QObject.__init__(self, parent) WidgetRegistry.__init__(self, other_or_parent) # Should the QStandardItemModel be subclassed? self.__item_model = QStandardItemModel(self) for i, desc in enumerate(self.categories()): cat_item = self._cat_desc_to_std_item(desc) self.__item_model.insertRow(i, cat_item) for j, wdesc in enumerate(self.widgets(desc.name)): widget_item = self._widget_desc_to_std_item(wdesc, desc) cat_item.insertRow(j, widget_item) def model(self): """ Return the widget descriptions in a Qt Item Model instance (QStandardItemModel). .. note:: The model should not be modified outside of the registry. """ return self.__item_model def item_for_widget(self, widget): """Return the QStandardItem for the widget. """ if isinstance(widget, six.string_types): widget = self.widget(widget) cat = self.category(widget.category) cat_ind = self.categories().index(cat) cat_item = self.model().item(cat_ind) widget_ind = self.widgets(cat).index(widget) return cat_item.child(widget_ind) def action_for_widget(self, widget): """ Return the QAction instance for the widget (can be a string or a WidgetDescription instance). """ item = self.item_for_widget(widget) return qtcompat.qunwrap(item.data(self.WIDGET_ACTION_ROLE)) def create_action_for_item(self, item): """ Create a QAction instance for the widget description item. """ name = item.text() tooltip = item.toolTip() whatsThis = item.whatsThis() icon = item.icon() if icon: action = QAction(icon, name, self, toolTip=tooltip, whatsThis=whatsThis, statusTip=name) else: action = QAction(name, self, toolTip=tooltip, whatsThis=whatsThis, statusTip=name) widget_desc = item.data(self.WIDGET_DESC_ROLE) action.setData(widget_desc) action.setProperty("item", qtcompat.qwrap(item)) return action def _insert_category(self, desc): """ Override to update the item model and emit the signals. """ priority = desc.priority priorities = [c.priority for c, _ in self.registry] insertion_i = bisect.bisect_right(priorities, priority) WidgetRegistry._insert_category(self, desc) cat_item = self._cat_desc_to_std_item(desc) self.__item_model.insertRow(insertion_i, cat_item) self.category_added.emit(desc.name, desc) def _insert_widget(self, category, desc): """ Override to update the item model and emit the signals. """ assert (isinstance(category, CategoryDescription)) categories = self.categories() cat_i = categories.index(category) _, widgets = self._categories_dict[category.name] priorities = [w.priority for w in widgets] insertion_i = bisect.bisect_right(priorities, desc.priority) WidgetRegistry._insert_widget(self, category, desc) cat_item = self.__item_model.item(cat_i) widget_item = self._widget_desc_to_std_item(desc, category) cat_item.insertRow(insertion_i, widget_item) self.widget_added.emit(category.name, desc.name, desc) def _cat_desc_to_std_item(self, desc): """ Create a QStandardItem for the category description. """ item = QStandardItem() item.setText(desc.name) if desc.icon: icon = desc.icon else: icon = "icons/default-category.svg" icon = icon_loader.from_description(desc).get(icon) item.setIcon(icon) if desc.background: background = desc.background else: background = DEFAULT_COLOR background = NAMED_COLORS.get(background, background) brush = QBrush(QColor(background)) item.setData(brush, self.BACKGROUND_ROLE) tooltip = desc.description if desc.description else desc.name item.setToolTip(tooltip) item.setFlags(Qt.ItemIsEnabled) item.setData(qtcompat.qwrap(desc), self.CATEGORY_DESC_ROLE) return item def _widget_desc_to_std_item(self, desc, category): """ Create a QStandardItem for the widget description. """ item = QStandardItem(desc.name) item.setText(desc.name) if desc.icon: icon = desc.icon else: icon = "icons/default-widget.svg" icon = icon_loader.from_description(desc).get(icon) item.setIcon(icon) # This should be inherited from the category. background = None if desc.background: background = desc.background elif category.background: background = category.background else: background = DEFAULT_COLOR if background is not None: background = NAMED_COLORS.get(background, background) brush = QBrush(QColor(background)) item.setData(brush, self.BACKGROUND_ROLE) tooltip = tooltip_helper(desc) style = "ul { margin-top: 1px; margin-bottom: 1px; }" tooltip = TOOLTIP_TEMPLATE.format(style=style, tooltip=tooltip) item.setToolTip(tooltip) item.setWhatsThis(whats_this_helper(desc)) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) item.setData(qtcompat.qwrap(desc), self.WIDGET_DESC_ROLE) # Create the action for the widget_item action = self.create_action_for_item(item) item.setData(qtcompat.qwrap(action), self.WIDGET_ACTION_ROLE) return item
class WebImageBatchDownloader(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self._init_task_list() def _init_task_list(self): self.model_task_list = QStandardItemModel(1, 3, self.ui.tableView_Tasks) self.model_task_list.setHorizontalHeaderLabels(["狀態", "網址", "本機儲存目錄"]) self.model_task_list.removeRow(0) self.ui.tableView_Tasks.setModel(self.model_task_list) self.ui.tableView_Tasks.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Fixed) self.ui.tableView_Tasks.horizontalHeader().setDefaultSectionSize(60) self.ui.tableView_Tasks.horizontalHeader().resizeSection(0, 60) self.ui.tableView_Tasks.horizontalHeader().resizeSection(1, 600) self.ui.tableView_Tasks.horizontalHeader().resizeSection(2, 250) self.ui.tableView_Tasks.verticalHeader().setDefaultSectionSize(20) def _model_setItem(self, row, col, data): self.model_task_list.setItem(row, col, QStandardItem(data)) def add_batch_url(self): self.ui.comboBox_batch_urls.addItem( self.ui.plainTextEdit_BatchUrl.text().rstrip()) self.ui.comboBox_batch_urls.setCurrentIndex( self.ui.comboBox_batch_urls.count() - 1) urls = self._analysis_batch_urls() self._update_tasks(urls) self._update_output_paths() def _analysis_batch_urls(self): url_interprer = pyddavid.web_image.UrlToComponentsInterpreter() batch_urls = [ self.ui.comboBox_batch_urls.itemText(i) for i in range(self.ui.comboBox_batch_urls.count()) ] for batch_url in batch_urls: url_interprer.add_urls_from_url_batch(batch_url) urls = url_interprer.get_urls() return urls def _update_tasks(self, urls): self.model_task_list.removeRows(0, self.model_task_list.rowCount()) for url in urls: current_row = self.model_task_list.rowCount() self.model_task_list.insertRow(current_row) self._model_setItem(current_row, 0, "未知") self._model_setItem(current_row, 1, url) def _adjust_root(self): root = self.ui.plainTextEdit_SaveDir.text().replace("\\", "/") self.ui.plainTextEdit_SaveDir.setText(root) def _update_output_paths(self): n_tasks = self.model_task_list.rowCount() root = self._get_root() level = self._get_level() for r in range(n_tasks): output_path = pyddavid.web_image.path_from_url_and_root( self.model_task_list.item(r, 1).text(), root, level) self._model_setItem(r, 2, output_path) self.ui.tableView_Tasks.setColumnWidth(2, 280) def remove_current_batch_url(self): if self.ui.comboBox_batch_urls.count() >= 0: self.ui.comboBox_batch_urls.removeItem( self.ui.comboBox_batch_urls.currentIndex()) urls = self._analysis_batch_urls() self._update_tasks(urls) self._update_output_paths() def choose_output_dir(self): self.ui.plainTextEdit_SaveDir.setText( QFileDialog.getExistingDirectory( self, "選擇存檔目錄", self.ui.plainTextEdit_SaveDir.text(), QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)) self._update_output_paths() def _get_root(self): root = self.ui.plainTextEdit_SaveDir.text() if root == "": root = "." return root def _get_level(self): level = int(self.ui.lineEdit_Level.text()) return level def save_img(self, index): url = self.model_task_list.item(index.row(), 1).text() output_path = self.model_task_list.item(index.row(), 2).text() output_dir, output_filename = pyddavid.web_image.split_path_to_dir_and_filename( output_path) if pyddavid.web_image.save_img_from_url(url, output_dir, output_filename): self._update_process_message("下載完成。") imshow(output_path, output_filename) else: self._update_process_message("下載失敗。") def test_urls(self): urls = [ self.model_task_list.item(r, 1).text() for r in range(self.model_task_list.rowCount()) ] self.thread_test_urls = TestUrlsThread(urls) self.thread_test_urls.start() self.thread_test_urls.process_message_updated.connect( self._update_process_message) self.thread_test_urls.process_task_updated.connect(self._model_setItem) def _update_process_message(self, message): self.ui.label_ProcessMessage.setText(message) def download_imgs(self): indexs = [] urls = [] output_paths = [] for r in range(self.model_task_list.rowCount()): if (self.model_task_list.item(r, 0).text() == "未知" or self.model_task_list.item(r, 0).text() == "可用"): indexs.append(r) urls.append(self.model_task_list.item(r, 1).text()) output_paths.append(self.model_task_list.item(r, 2).text()) root = self._get_root() self.save_image_thread = SaveImageThread( indexs, urls, output_paths, root, ) self.save_image_thread.start() self.save_image_thread.process_message_updated.connect( self._update_process_message) self.save_image_thread.process_task_updated.connect( self._model_setItem) def reset_all(self): self.ui.comboBox_batch_urls.clear() self.model_task_list.removeRows(0, self.model_task_list.rowCount())
class TIM(QWidget, Ui_Form): grouplist = [] userslist = [] tmpuseritem = [] def __init__(self): super().__init__() self.setupUi(self) self.Ui_init() self.menuflag = 1 self.setWindowFlag(Qt.FramelessWindowHint) #self.client = client def Ui_init(self): self.treeWidget.setIndentation(0) self.treeWidget.setColumnCount(1) self.treeWidget.setColumnWidth(0, 50) self.treeWidget.setHeaderLabels(['好友']) self.treeWidget.setIconSize(QSize(70, 70)) self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.treeWidget.currentItemChanged.connect(self.restatistic) self.treeWidget.itemClicked.connect(self.isclick) self.bt_adduser.clicked.connect(self.on_bt_adduser_clicked) self.bt_search.clicked.connect(self.on_bt_search_clicked) self.m_model = QStandardItemModel(0, 1, self) m_completer = QCompleter(self.m_model, self) self.lineEdit.setCompleter(m_completer) m_completer.activated[str].connect(self.onUsernameChoosed) root = self.creategroup('我的好友') root.setExpanded(True) self.lineEdit.textChanged[str].connect(self.on_lineEdit_textChanged) def creategroup(self, groupname): hidernum = 0 group = QTreeWidgetItem(self.treeWidget) groupdic = { 'group' : group, 'groupname' : groupname, 'childcount' : 0, 'childhide' : 0 } icon = self.searchIcon(groupname) group.setIcon(0, icon) randomnum = random.sample(range(26), 10) for i in randomnum: child = QTreeWidgetItem() randname, randicon, font, isvip, ishider = self.createusers(i) userdic = { 'user' : child, 'username' : randname, 'ishide' : 0 } self.userslist.append(userdic) child.setText(0, randname) child.setFont(0, font) child.setIcon(0, randicon) child.setTextAlignment(0, Qt.AlignHCenter | Qt.AlignVCenter) if isvip == 1: child.setForeground(0, QBrush(Qt.red)) child.setToolTip(0, '会员红名尊享') if ishider == 1: hidernum += 1 userdic['ishide'] = 1 group.addChild(child) childnum = group.childCount() lastchildnum = childnum - hidernum groupdic['childcount'] = childnum groupdic['childishide'] = hidernum groupname += ' ' + str(lastchildnum) + '/' + str(childnum) group.setText(0, groupname) self.grouplist.append(groupdic) return group def createusers(self, num): randname = "黑子" randicon = QIcon(str(num)+'.jpg') font = QFont() font.setPointSize(16) isvip = random.randint(0, 5) ishider = random.randint(0, 5) if ishider == 1: randicon = QIcon(str(num)+'h.jpg') return randname, randicon, font, isvip, ishider def searchIcon(self, gpname2): if gpname2.find('好友') >= 0: return QIcon('buddy.ico') elif gpname2.find('同事'): return QIcon('partner.ico') elif gpname2.find('黑名单'): return QIcon('blacklist.ico') else: return QIcon('defalut.ico') def mousePressEvent(self, event): if event.button()== Qt.LeftButton: self.m_drag=True self.m_DragPosition=event.globalPos()-self.pos() event.accept() def mouseMoveEvent(self, QMouseEvent): if QMouseEvent.buttons() and Qt.LeftButton: self.move(QMouseEvent.globalPos()-self.m_DragPosition) QMouseEvent.accept() def mouseReleaseEvent(self, QMouseEvent): self.m_drag=False def onUsernameChoosed(self, name): self.lineEdit.setText(name) def on_lineEdit_textChanged(self, text): namelist = [] for itm in self.userslist: username = itm['username'] if username.find(text) >= 0: namelist.append(itm['username']) self.m_model.removeRows(0, self.m_model.rowCount()) for i in range(0, len(namelist)): self.m_model.insertRow(0) self.m_model.setData(self.m_model.index(0, 0), namelist[i]) def on_bt_search_clicked(self): username = self.lineEdit.text() if len(username) > 0: useritemindex = self.searchuser(username) if useritemindex is not None: useritem = self.userslist[useritemindex]['user'] self.treeWidget.setCurrentItem(useritem) else: QMessageBox.information(self, '消息', '不存在此好友!') def on_bt_adduser_clicked(self): adduser = Dialog_additem() for g in self.grouplist: adduser.comboBox.addItem(g['groupname']) r = adduser.exec_() if r > 0: newitem = QTreeWidgetItem() newname = adduser.lineEdit.text() newicon = adduser.geticonpath() font = QFont() font.setPointSize(16) newitem.setFont(0, font) newitem.setText(0, newname) newitem.setTextAlignment(0, Qt.AlignHCenter | Qt.AlignVCenter) newitem.setIcon(0, QIcon(newicon)) comboxinfo = adduser.comboBox.currentText() cindex = self.searchgroup(comboxinfo) group = self.grouplist[cindex]['group'] self.grouplist[cindex]['childcount'] += 1 userdic = { 'user' : newitem, 'username' : newname, 'ishide' : 0 } self.userslist.append(userdic) group.addChild(newitem) self.treeWidget.setCurrentItem(newitem) def contextMenuEvent(self, event): hititem = self.treeWidget.currentItem() if hititem: root = hititem.parent() if root is None: #说明是一个分组 pgroupmenu = QMenu(self) pAddgroupAct = QAction('添加分组', self.treeWidget) pRenameAct = QAction('重命名', self.treeWidget) pDeleteAct = QAction('删除分组', self.treeWidget) pgroupmenu.addAction(pAddgroupAct) pgroupmenu.addAction(pRenameAct) pgroupmenu.addAction(pDeleteAct) pAddgroupAct.triggered.connect(self.addgroup) pRenameAct.triggered.connect(self.renamegroup) if self.treeWidget.itemAbove(hititem) is None: pDeleteAct.setEnabled(False) else: pDeleteAct.setEnabled(True) pDeleteAct.triggered.connect(self.deletegroup) pgroupmenu.popup(self.mapToGlobal(event.pos())) elif root.childCount() > 0: pItemmenu = QMenu(self) pDeleteItemAct = QAction('删除联系人', pItemmenu) pItemmenu.addAction(pDeleteItemAct) pDeleteItemAct.triggered.connect(self.delete) if len(self.grouplist) > 1: pSubMenu = QMenu('转移联系人至', pItemmenu) pItemmenu.addMenu(pSubMenu) for item_dic in self.grouplist: if item_dic['group'] is not root: pMoveAct = QAction(item_dic['groupname'], pItemmenu) pSubMenu.addAction(pMoveAct) pMoveAct.triggered.connect(self.moveItem) if len(self.getListitems(self.menuflag)) == 1: pRenameItemAct = QAction('设定备注', pItemmenu) pItemmenu.addAction(pRenameItemAct) pRenameItemAct.triggered.connect(self.renameItem) if self.menuflag > 0 and root.childCount() > 1: pBatchAct= QAction('分组内批量操作', pItemmenu) pItemmenu.addAction(pBatchAct) pBatchAct.triggered.connect(self.Batchoperation) elif self.menuflag < 0: pCancelBatchAct = QAction('取消批量操作', pItemmenu) pItemmenu.addAction(pCancelBatchAct) pCancelBatchAct.triggered.connect(self.CancelBatchoperation) pItemmenu.popup(self.mapToGlobal(event.pos())) def moveItem(self): movelist = self.getListitems(self.menuflag) togroupname = self.sender().text() mindex = self.searchgroup(togroupname) togroup = self.grouplist[mindex]['group'] self.deleteItems(movelist, flag = 0) self.add(togroup, movelist) self.tmpuseritem.clear() def delete(self): delitems = self.getListitems(self.menuflag) self.deleteItems(delitems) self.tmpuseritem.clear() def deleteItems(self, items, flag=1): for delitem in items: delitem.setData(0, Qt.CheckStateRole, QVariant()) pindex = delitem.parent().indexOfChild(delitem) dindex = self.searchuser(delitem) ishide = self.userslist[dindex]['ishide'] if flag == 1: del self.userslist[dindex] fathergroup = delitem.parent() findex = self.searchgroup(fathergroup) if ishide == 1: self.grouplist[findex]['childishide'] -= 1 self.grouplist[findex]['childcount'] -= 1 else: self.grouplist[findex]['childcount'] -= 1 delitem.parent().takeChild(pindex) def add(self, group, items): gindex = self.searchgroup(group) for item in items: aindex = self.searchuser(item) ishide = self.userslist[aindex]['ishide'] if ishide == 1: self.grouplist[gindex]['childishide'] += 1 self.grouplist[gindex]['childcount'] += 1 else: self.grouplist[gindex]['childcount'] += 1 group.addChild(item) self.treeWidget.setCurrentItem(item) def Batchoperation(self): self.menuflag *= -1 group = self.getListitems()[0].parent() childnum = group.childCount() for c in range(childnum): child = group.child(c) child.setCheckState(0, Qt.Unchecked) def CancelBatchoperation(self): self.menuflag *= -1 group = self.getListitems()[0].parent() childnum = group.childCount() for c in range(childnum): child = group.child(c) child.setData(0, Qt.CheckStateRole, QVariant()) def isclick(self, item): if item.checkState(0) == Qt.Checked: if self.tmpuseritem.count(item) == 0: self.tmpuseritem.append(item) else: if len(self.tmpuseritem) > 0: if self.tmpuseritem.count(item) != 0: i = self.tmpuseritem.index(item) del self.tmpuseritem[i] def renameItem(self): hituser = self.treeWidget.currentItem() uindex = self.searchuser(hituser) unewname, ok = QInputDialog.getText(self, '提示信息', '请输入备注名称') if ok: if len(unewname) == 0: QMessageBox.information(self, '提示', '备注名称不能为空') else: hituser.setText(0, unewname) self.userslist[uindex]['username'] = unewname def searchuser(self, hituser): if isinstance(hituser, str): for i, u in enumerate(self.userslist): if u['username'] == hituser: return i else: for i, u in enumerate(self.userslist): if hituser == u['user']: return i return None def getListitems(self, flag=1): if flag > 0: return self.treeWidget.selectedItems() else: return self.tmpuseritem def addgroup(self): gname, ok = QInputDialog.getText(self, '提示信息', '请输入分组名称') if ok: if len(gname) == 0: QMessageBox.information(self, '提示', '分组名称不能为空') else: self.creategroup(gname) def renamegroup(self): hitgroup = self.treeWidget.currentItem() gnewname, ok = QInputDialog.getText(self, '提示', '请输入新的分组名称') if ok: if len(gnewname) == 0: QMessageBox.information(self, '提示', '分组名称不能为空') else: hitgroup.setText(0, gnewname) newicon = self.searchIcon(hitgroup.text(0)) hitgroup.setIcon(0, newicon) gindex = self.searchgroup(hitgroup) self.grouplist[gindex]['groupname'] = gnewname self.treeWidget.setCurrentItem(hitgroup.child(0)) def deletegroup(self): hitgroup = self.treeWidget.currentItem() gindex = self.searchgroup(hitgroup) reply = QMessageBox.question(self, '警告', '确定要删除这个分组吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.treeWidget.takeTopLevelItem(gindex) del self.grouplist[gindex] def searchgroup(self, hitgroup): if isinstance(hitgroup, str): for i, g in enumerate(self.grouplist): if g['groupname'] == hitgroup: return i else: for i, g in enumerate(self.grouplist): if g['group'] == hitgroup: return i def restatistic(self, item, preitem): if item: fathergroup = item.parent() if fathergroup: self.restatistic_op(fathergroup) else: self.restatistic_op(item) elif preitem.parent().childCount() == 1: lastgroupname = preitem.parent().text(0).split()[0] + ' 0/0' preitem.parent().setText(0, lastgroupname) self.menuflag = 1 def restatistic_op(self, itemorgroup): gindex = self.searchgroup(itemorgroup) totalcount = self.grouplist[gindex]['childcount'] hidecount = self.grouplist[gindex]['childishide'] fathergroupname = self.grouplist[gindex]['groupname'] fathergroupname += ' ' + str(totalcount - hidecount) + '/' + str(totalcount) itemorgroup.setText(0, fathergroupname) def closeEvent(self, event): reply = QMessageBox.question(self, '提示', '确定要退出程序吗?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: event.ignore() else: self.client.dealQuit() event.accept()
class CustomTable(QTableView): """ CustomTable which inherits the QTableView Class. This implementation fixes an apparent issue with the QTableView where if you drag and drop internally The dragged item when dropped would overwrite the item it was dropped on and leave a hole in the table where the dragged item originates from. """ def __init__(self): super(QTableView, self).__init__() self.model = QStandardItemModel(1, 2) self.setModel(self.model) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.verticalHeader().hide() self.model.setColumnCount(2) self.model.setHorizontalHeaderLabels( ["Original Files", "New Name - Preview"]) self.setAlternatingRowColors(True) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setMinimumHeight(300) self.setDragEnabled(True) self.setAcceptDrops(True) self.setDropIndicatorShown(True) self.setDragDropOverwriteMode(False) self.setDefaultDropAction(QtCore.Qt.MoveAction) self.setDragDropMode(QAbstractItemView.InternalMove) header = self.horizontalHeader() header.setSectionResizeMode(QHeaderView.Stretch) def dropEvent(self, event): """ overwrite drop event to handle drop events how we need to drop the item. """ # The QTableWidget from which selected rows will be moved sender = event.source() # GET ROW BEING DROPPED drop_row = self.model.itemFromIndex(self.indexAt(event.pos())).row() # GET SELECTED ITEMS selected_items = sender.get_selected_items() # MOVE ITEM for data in selected_items: if data.text(): checked = data.checkState() new_item = QStandardItem(data.text()) new_item.setCheckState(checked) new_item.setCheckable(True) self.model.insertRow(drop_row, new_item) event.accept() def get_selected_items(self): """ method used to return a list of selected items Returns: list """ selected_rows = [] for index in self.selectedIndexes(): item = self.model.itemFromIndex(index) if item not in selected_rows: selected_rows.append(item) selected_rows.sort() return selected_rows
class BatchWindow(QMainWindow, BATCH_WIDGET): """ The batch sir tracker application window """ NAME, \ RUN, \ PARTICLE_COUNT, \ SCORE_TYPE, \ FILTER_MODE, \ UPDATE_INTERVAL, \ UPDATE_METHOD, \ HISTORICAL_LENGTH, \ STATUS = range(9) def __init__(self, parent=None): super(BatchWindow, self).__init__(parent) BATCH_WIDGET.__init__(self) self.setupUi(self) self.create_run_model(self) self.tv_runs.clicked.connect(self.on_tv_runs_clicked) self.btn_load.clicked.connect(self.do_load) self.btn_start.clicked.connect(self.do_start) self.btn_cancel.clicked.connect(self.do_cancel) self.options = {} self.btn_start.setEnabled(False) self.btn_cancel.setEnabled(False) self.runs = None self.threadpool = QThreadPool() self.viewer_index = None self.viewer = SIRWindow(self) @pyqtSlot() def do_load(self): """ load batch parameters from a file """ options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog filename, _ = QFileDialog.getOpenFileName( self, "QfileDialog.getOpenFileName()", "", "Json Files (*.json)", options=options) if not filename: self.btn_start.setEnabled(False) return with open(filename, 'r') as bo_file: self.options = json.load(bo_file) batch_details = (f"Source root: {self.options['root_path']}\n" f"Save path: {self.options['save_path']}") self.lbl_batch_details.setText(batch_details) self.runs = [ { 'job_options': { 'name': sequence['name'], 'start_frame': sequence['start_frame'], 'end_frame': sequence['end_frame'], 'particle_count': particle_count, 'score_type': score_type, 'filter_mode': filter_mode, 'update_interval': update_interval, 'update_method': update_method, 'historical_length': historical_length, 'run': run, 'root_path': self.options['root_path'], 'save_path': self.options['save_path'], }, 'status': 'Not started' } for sequence in self.options['sequences'] for particle_count in self.options['particle_counts'] for score_type in self.options['score_types'] for filter_mode in self.options['filter_modes'] for update_interval in self.options['update_intervals'] for update_method in self.options['update_methods'] for historical_length in self.options['historical_lengths'] for run in range(self.options['number_runs']) ] # attach run ids, seed, and tracker objects for index, r in enumerate(self.runs): r['job_options']['job_id'] = index r['job_options']['seed'] = r['job_options']['run'] r['tracker'] = SIRTracker(r['job_options']) r['tracker'].signals.status_changed.connect(self.on_status_change) # add to display self.clear_runs() for ro_idx in range(len(self.runs)): run_options = self.runs[ro_idx]['job_options'] self.add_run(run_options, self.runs[ro_idx]['status']) self.btn_start.setEnabled(True) @pyqtSlot() def do_start(self): """ start button callback """ self.btn_load.setEnabled(False) self.btn_start.setEnabled(False) self.btn_cancel.setEnabled(True) for r in self.runs: self.threadpool.start(r['tracker']) @pyqtSlot(int, str) def on_status_change(self, job_id, status): """ a job status has changed """ self.update_status(job_id, status) @pyqtSlot() def do_cancel(self): """ cancel button callback """ pass def create_run_model(self, parent): """ set model for the list(tree) of batch entries """ self.model = QStandardItemModel(0, 9, parent) self.model.setHeaderData(self.NAME, Qt.Horizontal, "Name") self.model.setHeaderData(self.RUN, Qt.Horizontal, "Run Index") self.model.setHeaderData(self.PARTICLE_COUNT, Qt.Horizontal, "particles") self.model.setHeaderData(self.SCORE_TYPE, Qt.Horizontal, "Score Type") self.model.setHeaderData(self.FILTER_MODE, Qt.Horizontal, "Filter Mode") self.model.setHeaderData(self.UPDATE_INTERVAL, Qt.Horizontal, "Update Interval") self.model.setHeaderData(self.UPDATE_METHOD, Qt.Horizontal, "Update Method") self.model.setHeaderData(self.HISTORICAL_LENGTH, Qt.Horizontal, "History Length") self.model.setHeaderData(self.STATUS, Qt.Horizontal, "Status") self.tv_runs.setModel(self.model) def add_run(self, run_options, status): """ add a run to the list """ row_idx = self.model.rowCount() self.model.insertRow(row_idx) self.model.setData(self.model.index(row_idx, self.NAME), run_options['name']) self.model.setData(self.model.index(row_idx, self.RUN), run_options['run']) self.model.setData(self.model.index(row_idx, self.PARTICLE_COUNT), run_options['particle_count']) self.model.setData(self.model.index(row_idx, self.SCORE_TYPE), run_options['score_type']) self.model.setData(self.model.index(row_idx, self.FILTER_MODE), run_options['filter_mode']) self.model.setData(self.model.index(row_idx, self.UPDATE_INTERVAL), run_options['update_interval']) self.model.setData(self.model.index(row_idx, self.UPDATE_METHOD), run_options['update_method']) self.model.setData(self.model.index(row_idx, self.HISTORICAL_LENGTH), run_options['historical_length']) self.model.setData(self.model.index(row_idx, self.STATUS), status) def update_status(self, index, status): """ update status of a run given its index """ self.runs[index]['status'] = status self.model.setData(self.model.index(index, self.STATUS), status) def clear_runs(self): """ clear run list """ self.model.removeRows(0, self.model.rowCount()) @pyqtSlot(QModelIndex) def on_tv_runs_clicked(self, index): """ list selection changed """ row_idx = index.row() self.viewer.show() self.viewer_index = row_idx self.viewer.attach_tracker(self.runs[row_idx]['tracker'])
class YoutubeDLGui(QMainWindow): def __init__(self): super(YoutubeDLGui, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) Center(self) self.download_model = QStandardItemModel(0, 5, self) self.download_model.setHeaderData(0, QtCore.Qt.Horizontal, 'Name') self.download_model.setHeaderData(1, QtCore.Qt.Horizontal, 'Progress') self.download_model.setHeaderData(2, QtCore.Qt.Horizontal, 'Size') self.download_model.setHeaderData(3, QtCore.Qt.Horizontal, 'ETA') self.download_model.setHeaderData(4, QtCore.Qt.Horizontal, 'Speed') self.ui.downloadView.setModel(self.download_model) self.pending_model = QStandardItemModel(0, 2, self) self.pending_model.setHeaderData(0, QtCore.Qt.Horizontal, 'Name') self.pending_model.setHeaderData(1, QtCore.Qt.Horizontal, 'Quality') self.ui.pendingView.setModel(self.pending_model) self.ui.pendingView.setItemDelegate(CustomToolTipDelegate(self.ui.pendingView)) self.init_status_bar() self.parsing_worker = WorkerBuilder.build(bool) self.pending_list = [] def init_status_bar(self): self.pending_progressbar = QProgressBar() self.pending_progressbar.setFixedHeight(20) self.pending_progressbar.setFixedWidth(150) self.pending_progressbar.setMaximum(0) self.pending_progressbar.setMinimum(0) self.pending_label = QLabel("") self.pending_label.setAlignment(QtCore.Qt.AlignLeading) self.pending_label.setFixedWidth(220) font = self.pending_label.font() font.setPointSize(10) self.pending_label.setFont(font) self.pending_label.setStyleSheet("padding-left: 5px") self.pending_progressbar.setVisible(False) self.statusBar().addPermanentWidget(self.pending_progressbar) self.statusBar().addWidget(self.pending_label) @pyqtSlot() def on_addBtn_clicked(self): url = CustomInputDialog.get_text("Url", "Enter Url") if not url[1]: return if not validators.url(url[0]): QMessageBox.information(self, "Invalid Url", "Please enter a valid url") self.on_addBtn_clicked() ydl_logger = YDLLogger() ydl_logger.debug_message.connect(self.on_debug_message_emitted) ydl_opt = { 'logger': ydl_logger } self.ui.addBtn.setEnabled(False) self.parser = InfoParser(url[0], ydl_opt) self.parsing_worker.set_up(self.parser.generate_info, self.on_parsing_done) self.parsing_worker.start() self.pending_progressbar.setVisible(True) @pyqtSlot(int) def on_combobox_currentIndexChanged(self, index): list_index = self.ui.pendingView.currentIndex().row() self.pending_list[list_index].current_format = self.pending_list[list_index].format_info[index] @pyqtSlot(str) def on_debug_message_emitted(self, msg): self.pending_label.setText(msg) def add_to_pending(self, ydl_obj): if ydl_obj in self.pending_list: return index = len(self.pending_list) self.pending_list.append(ydl_obj) self.pending_model.insertRow(index) self.pending_model.setData(self.pending_model.index(index, 0), ydl_obj.title) model_index = self.pending_model.index(index, 0) self.ui.pendingView.setCurrentIndex(model_index) self.ui.pendingView.selectionModel().select(model_index, QItemSelectionModel.ClearAndSelect) combobox = QComboBox() combobox.currentIndexChanged[int].connect(self.on_combobox_currentIndexChanged) for ydl_format in ydl_obj.info: format_text = "%s, %s, %s" % (ydl_format['extension'], ydl_format['resolution'], ydl_format['filesize']) combobox.addItem(format_text) self.ui.pendingView.setIndexWidget(self.pending_model.index(index, 1), combobox) self.ui.tabWidget.setCurrentIndex(1) def on_parsing_done(self, success): self.pending_progressbar.setVisible(False) self.pending_label.setText("") self.ui.addBtn.setEnabled(True) if success: self.add_to_pending(self.parser.ydl_object) else: self.parsing_worker.quit() self.ui.addBtn.setEnabled(True) QMessageBox.information(self, "Invalid Url", "Unable to parse url")
class QmyMainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setCentralWidget(self.ui.qSplitter) self.__ColCount = 6 self.itemModel = QStandardItemModel(5, self.__ColCount, self) self.selectionModel = QItemSelectionModel(self.itemModel) self.selectionModel.currentChanged.connect(self.do_curChanged) self.__lastColumnTitle = "测井取样" self.__lastColumnFlags = (Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) self.ui.qTableView.setModel(self.itemModel) self.ui.qTableView.setSelectionModel(self.selectionModel) oneOrMore = QAbstractItemView.ExtendedSelection self.ui.qTableView.setSelectionMode(oneOrMore) itemOrRow = QAbstractItemView.SelectItems self.ui.qTableView.setSelectionBehavior(itemOrRow) self.ui.qTableView.verticalHeader().setDefaultSectionSize(22) self.ui.qTableView.setAlternatingRowColors(True) self.ui.qTableView.setEnabled(False) self.qLabel1 = QLabel("当前单元格:", self) self.qLabel1.setMinimumWidth(180) self.qLabel2 = QLabel("单元格内容:", self) self.qLabel2.setMinimumWidth(150) self.qLabel3 = QLabel("当前文件:", self) self.ui.qStatusBar.addWidget(self.qLabel1) self.ui.qStatusBar.addWidget(self.qLabel2) self.ui.qStatusBar.addPermanentWidget(self.qLabel3) self.spinCeshen = QmyFloatSpinDelegate(0, 10000, 0, self) self.spinLength = QmyFloatSpinDelegate(0, 6000, 2, self) self.spinDegree = QmyFloatSpinDelegate(0, 360, 1, self) self.ui.qTableView.setItemDelegateForColumn(0, self.spinCeshen) self.ui.qTableView.setItemDelegateForColumn(1, self.spinLength) self.ui.qTableView.setItemDelegateForColumn(3, self.spinLength) self.ui.qTableView.setItemDelegateForColumn(2, self.spinDegree) qualities = ["优", "良", "合格", "不合格"] self.comboDelegate = QmyComboBoxDelegate(self) self.comboDelegate.setItems(qualities, False) self.ui.qTableView.setItemDelegateForColumn(4, self.comboDelegate) def __iniModelFromStringList(self, allLines): rowCnt = len(allLines) self.itemModel.setRowCount(rowCnt - 1) headerText = allLines[0].strip() headerList = headerText.split("\t") self.itemModel.setHorizontalHeaderLabels(headerList) self.__lastColumnTitle = headerList[len(headerList) - 1] lastColNo = self.__ColCount - 1 for i in range(rowCnt - 1): lineText = allLines[i + 1].strip() strList = lineText.split("\t") for j in range(self.__ColCount - 1): item = QStandardItem(strList[j]) self.itemModel.setItem(i, j, item) item = QStandardItem(self.__lastColumnTitle) item.setFlags(self.__lastColumnFlags) item.setCheckable(True) if (strList[lastColNo] == "0"): item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Checked) self.itemModel.setItem(i, lastColNo, item) def __setCellAlignment(self, align=Qt.AlignHCenter): if (not self.selectionModel.hasSelection()): return selectedIndex = self.selectionModel.selectedIndexes() count = len(selectedIndex) for i in range(count): index = selectedIndex[i] item = self.itemModel.itemFromIndex(index) item.setTextAlignment(align) @pyqtSlot() def on_qAction1_triggered(self): # 打开文件 curPath = os.getcwd() filename, flt = QFileDialog.getOpenFileName( self, "打开一个文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return self.qLabel3.setText("当前文件:" + filename) self.ui.qPlainTextEdit.clear() aFile = open(filename, 'r') allLines = aFile.readlines() aFile.close() for strLine in allLines: self.ui.qPlainTextEdit.appendPlainText(strLine.strip()) self.__iniModelFromStringList(allLines) self.ui.qTableView.setEnabled(True) self.ui.qAction2.setEnabled(True) self.ui.qAction3.setEnabled(True) self.ui.qAction4.setEnabled(True) self.ui.qAction5.setEnabled(True) self.ui.qAction6.setEnabled(True) @pyqtSlot() def on_qAction2_triggered(self): # 另存文件 curPath = os.getcwd() filename, flt = QFileDialog.getSaveFileName( self, "保存文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return self.on_qAction3_triggered() aFile = open(filename, "w") aFile.write(self.ui.qPlainTextEdit.toPlainText()) aFile.close() @pyqtSlot() def on_qAction4_triggered(self): # 添加行 itemList = [] for i in range(self.__ColCount - 1): item = QStandardItem("0") itemList.append(item) item = QStandardItem(self.__lastColumnTitle) item.setCheckable(True) item.setFlags(self.__lastColumnFlags) itemList.append(item) self.itemModel.appendRow(itemList) curIndex = self.itemModel.index(self.itemModel.rowCount() - 1, 0) self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() def on_qAction5_triggered(self): # 插入行 itemlist = [] for i in range(self.__ColCount - 1): item = QStandardItem("0") itemlist.append(item) item = QStandardItem(self.__lastColumnTitle) item.setFlags(self.__lastColumnFlags) item.setCheckable(True) item.setCheckState(Qt.Checked) itemlist.append(item) curIndex = self.selectionModel.currentIndex() self.itemModel.insertRow(curIndex.row(), itemlist) self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() def on_qAction6_triggered(self): # 删除行 curIndex = self.selectionModel.currentIndex() self.itemModel.removeRow(curIndex.row()) @pyqtSlot() def on_qAction7_triggered(self): # 居左 self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter) @pyqtSlot() def on_qAction8_triggered(self): # 居中 self.__setCellAlignment(Qt.AlignHCenter | Qt.AlignVCenter) @pyqtSlot() def on_qAction9_triggered(self): # 居右 self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter) @pyqtSlot(bool) def on_qAction10_triggered(self, checked): # 粗体 if (not self.selectionModel.hasSelection()): return selectedIndex = self.selectionModel.selectedIndexes() count = len(selectedIndex) for i in range(count): index = selectedIndex[i] item = self.itemModel.itemFromIndex(index) font = item.font() font.setBold(checked) item.setFont(font) @pyqtSlot() def on_qAction3_triggered(self): # 模型数据 self.ui.qPlainTextEdit.clear() lineStr = "" for i in range(self.itemModel.columnCount() - 1): item = self.itemModel.horizontalHeaderItem(i) lineStr = lineStr + item.text() + "\t" item = self.itemModel.horizontalHeaderItem(self.__ColCount - 1) lineStr = lineStr + item.text() self.ui.qPlainTextEdit.appendPlainText(lineStr) for i in range(self.itemModel.rowCount()): lineStr = "" for j in range(self.itemModel.columnCount() - 1): item = self.itemModel.item(i, j) lineStr = lineStr + item.text() + "\t" item = self.itemModel.item(i, self.__ColCount - 1) if (item.checkState() == Qt.Checked): lineStr = lineStr + "1" else: lineStr = lineStr + "0" self.ui.qPlainTextEdit.appendPlainText(lineStr) def do_curChanged(self, current, previous): if (current != None): text = "当前单元格:%d行,%d列" % (current.row(), current.column()) self.qLabel1.setText(text) item = self.itemModel.itemFromIndex(current) self.qLabel2.setText("单元格内容:" + item.text()) font = item.font() self.ui.qAction10.setChecked(font.bold())
class MyWin(QtWidgets.QMainWindow): def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) self.ui = MainWindow.Ui_MainWindow() self.ui.setupUi(self) self.ui.action.triggered.connect(self.action_trigger) self.ui.action_5.triggered.connect(self.show_settings) self.ui.action_3.triggered.connect(self.action_3_trigger) self.ui.action_2.triggered.connect(qApp.quit) self.ui.toolButton_2.clicked.connect(self.button_pause) self.ui.toolButton.clicked.connect(self.button_play) self.ui.toolButton_3.clicked.connect(self.button_stop) self.model = QStandardItemModel(0, 2, parent) self.model.setHeaderData(0, Qt.Horizontal, "Объект") self.model.setHeaderData(1, Qt.Horizontal, "Кол-во совпадений") self.ui.treeView.setModel(self.model) for i in range(22): self.model.insertRow(i) self.ui.MplWidget.canvas.axes.clear() self.ui.MplWidget.canvas.axes.set_title('Суммарное количество') self.ui.MplWidget.canvas.axes.set_facecolor('0.93') self.ui.MplWidget.canvas.axes.grid(True, color='1.0', linestyle='-') self.ui.MplWidget.canvas.axes.spines['top'].set_color('white') self.ui.MplWidget.canvas.axes.spines['bottom'].set_color('white') self.ui.MplWidget.canvas.axes.spines['right'].set_color('white') self.ui.MplWidget.canvas.axes.spines['left'].set_color('white') self.ui.MplWidget.canvas.axes.ticklabel_format(style='plain', axis='x', useOffset=False) for axis in [ self.ui.MplWidget.canvas.axes.xaxis, self.ui.MplWidget.canvas.axes.yaxis ]: axis.set_major_locator(ticker.MaxNLocator(integer=True)) self.ui.MplWidget.canvas.draw() self.settings = Settings('config/settings.json') self.settings.load_json() self.accessLabelVideo = True self.pathOpen = None self.pathSave = None self.vebcam = None self.isSave = None self.stateVideo = VideoState.VIDEO_STOP self.prototx = 'config/MobileNetSSD_deploy.prototxt.txt' self.caffemodel = 'config/MobileNetSSD_deploy.caffemodel' self.action_trigger() def button_pause(self): self.stateVideo = VideoState.VIDEO_PAUSE def button_play(self): self.__start_playing_video() def button_stop(self): self.stateVideo = VideoState.VIDEO_STOP @pyqtSlot() def clear_image(self): self.ui.label.clear() def show_settings(self): self.myapp = STGWindow(self.settings, self) self.myapp.show() def __start_playing_video(self): if self.stateVideo == VideoState.VIDEO_STOP: if not self.pathOpen and not self.vebcam: QtWidgets.QMessageBox.about(self, "Ошибка", "Не указан источник") return self.stateVideo = VideoState.VIDEO_START self.th = Thread(self.prototx, self.caffemodel, self.pathOpen if not self.vebcam else 0, self.pathSave, self.settings, self) self.th.changePixmap.connect(self.set_image) self.th.printLog.connect(self.print_log) self.th.changeStatic.connect(self.set_statistic) self.th.clearPixmap.connect(self.clear_image) self.th.start() self.moveToThread(self.th) elif self.stateVideo == VideoState.VIDEO_PAUSE: self.stateVideo = VideoState.VIDEO_START # QtWidgets.QMessageBox.about(self, "Ошибка", "Сначала завершите текущий сеанс") def action_3_trigger(self): self.__start_playing_video() # Работа с графиком @pyqtSlot(dict, int) def set_statistic(self, total_visits: dict, count_frames: int): self.ui.MplWidget.canvas.axes.clear() self.ui.MplWidget.canvas.axes.grid(True) for dct in total_visits.values(): if any(item != 0 for item in dct['counts'][-100:]): color = tuple([(1 / 255) * i for i in dct['color']]) self.ui.MplWidget.canvas.axes.plot(dct['counts'][-100:], color=color) for axis in [ self.ui.MplWidget.canvas.axes.xaxis, self.ui.MplWidget.canvas.axes.yaxis ]: axis.set_major_locator(ticker.MaxNLocator(integer=True)) self.ui.MplWidget.canvas.draw() i = 0 for k, v in total_visits.items(): self.model.setData(self.model.index(i, 0), k) self.model.setData(self.model.index(i, 1), v['counts'][-1]) i += 1 @pyqtSlot(QImage) def set_image(self, image): self.ui.label.setPixmap(QPixmap.fromImage(image)) self.accessLabelVideo = True @pyqtSlot(str, bool) def print_log(self, value, is_clear: bool = False): self.ui.plainTextEdit.moveCursor(QTextCursor.End) if is_clear: self.ui.plainTextEdit.clear() if type(value) is dict: for key, value in value.items(): self.ui.plainTextEdit.insertPlainText('\n[%s]: %s' % (key, value)) else: self.ui.plainTextEdit.insertPlainText('\n' + str(value)) def action_trigger(self): self.myapp = OSWindow(self, self.getvar) self.myapp.show() def getvar(self, **kwargs): self.vebcam = kwargs.get('vebcam', None) self.isSave = kwargs.get('save', None) self.pathSave = kwargs.get('pathSave', None) self.pathOpen = kwargs.get('pathOpen', None)
class Table(QWidget): def __init__(self, name, data, columns=None, index=False, checkable=False, parent=None): QWidget.__init__(self, parent) self.name = name self.index = index self.checkable = checkable if not any([data, columns]): self.columns = [] else: self.columns = columns if columns else list(data[0].keys()) if checkable: self.columns.insert(0, '') if index: self.columns.insert(0, 'ID') self.setData(data) self.initUI() def initUI(self): # Layout UI elements of table mainLayout = QVBoxLayout() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.sourceModel = QStandardItemModel(0, len(self.columns), self) for i, column in enumerate(self.columns): self.sourceModel.setHeaderData(i, Qt.Horizontal, column) self.proxyModel.setSourceModel(self.sourceModel) self.proxyGroupBox = QGroupBox(self.name) self.proxyView = DeselectableTreeView() self.proxyView.setRootIsDecorated(False) self.proxyView.setAlternatingRowColors(True) self.proxyView.setModel(self.proxyModel) if not self.checkable: self.proxyView.setSortingEnabled(True) self.proxyView.sortByColumn(0, Qt.AscendingOrder) self.proxyView.setEditTriggers(QAbstractItemView.NoEditTriggers) proxyLayout = QGridLayout() proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3) self.proxyGroupBox.setLayout(proxyLayout) mainLayout.addWidget(self.proxyGroupBox) self.setLayout(mainLayout) self.update(self.data) def setSourceModel(self, model): self.proxyModel.setSourceModel(model) def setData(self, data): self.data = [] for i, item in enumerate(data): d = {} for col in self.columns: if col == 'ID': d[col] = item.get(col, i + 1) else: d[col] = item.get(col) self.data.append(d) #self.data = [{k: item.get(k, i+1) for k in self.columns} for i, item in enumerate(data)] def sortBy(self, colName): idx = 0 try: idx = self.columns.index(colName) except: pass self.proxyView.sortByColumn(idx, Qt.AscendingOrder) def rowCount(self): return self.sourceModel.rowCount() def columnCount(self): return self.sourceModel.columnCount() def addRow(self, row_i, rowData): self.sourceModel.insertRow(row_i) for col_i, data in enumerate(rowData.values()): if self.checkable and col_i == 0: self.proxyView.setColumnWidth(col_i, 1) item = QStandardItem(True) item.setCheckable(True) item.setCheckState(False) self.sourceModel.setItem(row_i, col_i, item) else: self.sourceModel.setData(self.sourceModel.index(row_i, col_i), data) def update(self, data): self.setData(data) self.sourceModel.removeRows(0, self.sourceModel.rowCount()) for i, data in enumerate(self.data): self.addRow(i, data) def getSelectedRowIndex(self): ''' Returns the index of the selected row from the source model ''' try: return self.proxyModel.mapToSource( self.proxyView.selectedIndexes()[0]).row() except: return False def getCheckedRowData(self): selectedData = [] for row_i in range(self.sourceModel.rowCount()): item = self.sourceModel.item(row_i, 0) if item.checkState(): selectedData.append(self.data[row_i]) return selectedData
class MessageList(MyTreeView): class Columns(IntEnum): HEIGHT = 0 FROM = 1 DATA = 2 filter_columns = [Columns.HEIGHT, Columns.FROM, Columns.DATA] ROLE_SORT_ORDER = Qt.UserRole + 1000 ROLE_ASSET_STR = Qt.UserRole + 1001 def __init__(self, parent): super().__init__(parent, self.create_menu, stretch_column=self.Columns.DATA, editable_columns=[]) self.wallet = self.parent.wallet self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSortingEnabled(True) self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=self.ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.update() self.sortByColumn(self.Columns.HEIGHT, Qt.AscendingOrder) self.messages = {} def webopen_safe(self, url): show_warn = self.parent.config.get('show_ipfs_warning', True) if show_warn: cb = QCheckBox(_("Don't show this message again.")) cb_checked = False def on_cb(x): nonlocal cb_checked cb_checked = x == Qt.Checked cb.stateChanged.connect(on_cb) goto = self.parent.question(_( 'You are about to visit:\n\n' '{}\n\n' 'IPFS hashes can link to anything. Please follow ' 'safe practices and common sense. If you are unsure ' 'about what\'s on the other end of an IPFS, don\'t ' 'visit it!\n\n' 'Are you sure you want to continue?').format(url), title=_('Warning: External Data'), checkbox=cb) if cb_checked: self.parent.config.set_key('show_ipfs_warning', False) if goto: webopen(url) else: webopen(url) def mouseDoubleClickEvent(self, event: QMouseEvent): idx = self.indexAt(event.pos()) if not idx.isValid(): return # Get the IPFS from 3rd column hm_idx = self.model().mapToSource(self.model().index(idx.row(), 2)) data = self.std_model.data(hm_idx) if data[:2] == 'Qm': # If it starts with Qm, it's an IPFS url = ipfs_explorer_URL(self.parent.config, 'ipfs', data) self.webopen_safe(url) def refresh_headers(self): headers = { self.Columns.HEIGHT: _('Height'), self.Columns.FROM: _('From'), self.Columns.DATA: _('Data'), } self.update_headers(headers) @profiler def update(self): if self.maybe_defer_update(): return self.messages = self.wallet.get_messages() self.proxy.setDynamicSortFilter( False) # temp. disable re-sorting after every change self.std_model.clear() self.refresh_headers() set_message = None for height, data in self.messages.items(): for d in data: is_from = d[0] message_txt = d[1] if not self.parent.config.get('get_dev_notifications', True) and d[2] is None: # The source will only be null if this is a dev notification continue # create item labels = [height, is_from, message_txt] asset_item = [QStandardItem(e) for e in labels] # align text and set fonts for i, item in enumerate(asset_item): item.setTextAlignment(Qt.AlignVCenter) # add item count = self.std_model.rowCount() self.std_model.insertRow(count, asset_item) self.set_current_idx(set_message) self.filter() self.proxy.setDynamicSortFilter(True) def add_copy_menu(self, menu, idx): cc = menu.addMenu(_("Copy")) for column in self.Columns: if self.isColumnHidden(column): continue column_title = self.model().headerData(column, Qt.Horizontal) hm_idx = self.model().mapToSource(self.model().index( idx.row(), column)) column_data = self.std_model.data(hm_idx) cc.addAction(column_title, lambda text=column_data, title=column_title: self. place_text_on_clipboard(text, title=title)) return cc def create_menu(self, position): org_idx: QModelIndex = self.indexAt(position) menu = QMenu() self.add_copy_menu(menu, org_idx) menu.exec_(self.viewport().mapToGlobal(position)) def place_text_on_clipboard(self, text: str, *, title: str = None) -> None: if is_address(text): try: self.wallet.check_address_for_corruption(text) except InternalAddressCorruption as e: self.parent.show_error(str(e)) raise super().place_text_on_clipboard(text, title=title) def get_edit_key_from_coordinate(self, row, col): return None # We don't edit anything here def on_edited(self, idx, edit_key, *, text): pass
class gcodeFile(QObject): ''' Gestion d'un fichier GCode dans la QListView de l'interface graphique reservee a cet usage Methodes : - __init__(QListView) -> Initialise et definit les elements de l'UI qui recevront le contenu du fichier - showFileOpen() -> Affiche la boite de dialogue d'ouverture - showFileSave() -> Affiche la boite de dialogue d'enregistrement - readFile(filePath) -> Charge un fichier dans la QListView - saveFile(filePath) -> Enregistre le contenu de la QListView dans un fichier - closeFile() -> Vide la QListView - setGcodeChanged(bool) -> Definit si le contenu de la liste a ete modifie depuis la lecture ou l'enregistrement du fichier - bool = gcodeChanged() -> Renvoi vrai si le contenu de la liste a ete modifie depuis la lecture ou l'enregistrement du fichier ''' sig_log = pyqtSignal(int, str) # Message de fonctionnement du composant def __init__(self, gcodeFileUi: QListView): super().__init__() self.__filePath = "" self.__gcodeFileUi = gcodeFileUi self.__gcodeFileUiModel = QStandardItemModel(self.__gcodeFileUi) self.__gcodeFileUiModel.itemChanged.connect(self.on_gcodeChanged) self.__gcodeCharge = False self.__gcodeChanged = False def showFileOpen(self): ''' Affiche la boite de dialogue d'ouverture ''' ''' if sys.platform == 'linux': # Prépare la boite de dialogue dialog = Gtk.FileChooserDialog( self.tr("Open a GCode file"), self, Gtk.FileChooserAction.OPEN, ( Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK ) ) dialog.set_local_only(False) # Permet l'affichage des fichiers réseaux sous Linux GTK+3 dialog_filter = Gtk.FileFilter() dialog_filter.set_name(self.tr("GCode file")) dialog_filter.add_pattern("*.gcode") dialog_filter.add_pattern("*.ngc") dialog_filter.add_pattern("*.nc") dialog_filter.add_pattern("*.gc") dialog_filter.add_pattern("*.cnc") dialog.add_filter(dialog_filter) # Affiche la boite de dialogue response = dialog.run() # Traite la réponse if response == Gtk.ResponseType.OK: print("Open clicked") print("File selected: " + dialog.get_filename()) elif response == Gtk.ResponseType.CANCEL: print("Cancel clicked") # Libère les ressources dialog.destroy() else: # sys.platform == 'linux' ''' opt = QtWidgets.QFileDialog.Options() ###opt |= QtWidgets.QFileDialog.DontUseNativeDialog fName = QtWidgets.QFileDialog.getOpenFileName( None, self.tr("Open a GCode file"), "", self.tr("GCode file (*.gcode *.ngc *.nc *.gc *.cnc)"), options=opt) return fName def readFile(self, filePath: str): self.sig_log.emit(logSeverity.info.value, self.tr("Reading file: {}").format(filePath)) try: f = open(filePath, 'r') lignes = f.readlines() f.close() self.sig_log.emit( logSeverity.info.value, self.tr("{} lines in the file").format(len(lignes))) # Envoi du contenu dans la liste self.__gcodeFileUiModel.clear() for l in lignes: item = QStandardItem(l.strip()) self.__gcodeFileUiModel.appendRow(item) self.__gcodeFileUi.setModel(self.__gcodeFileUiModel) # Selectionne la premiere ligne du fichier dans la liste self.selectGCodeFileLine(0) # Selectionne l'onglet du fichier except Exception as e: self.sig_log.emit( logSeverity.error.value, self.tr("Reading file error: {}").format(filePath)) self.sig_log.emit(logSeverity.error.value, str(e)) self.__gcodeFileUiModel.clear() self.__filePath = "" self.__gcodeChanged = False return False # Pas d'erreur self.__gcodeCharge = True self.__filePath = filePath self.__gcodeChanged = False return True def isFileLoaded(self): return self.__gcodeCharge def filePath(self): return self.__filePath def fileName(self): return os.path.basename(self.__filePath) def selectGCodeFileLine(self, num: int): ''' Selectionne un element de la liste du fichier GCode ''' idx = self.__gcodeFileUiModel.index(num, 0, QModelIndex()) self.__gcodeFileUi.selectionModel().clearSelection() self.__gcodeFileUi.selectionModel().setCurrentIndex( idx, QItemSelectionModel.SelectCurrent) def getGCodeSelectedLine(self): ''' Renvoie le N° (0 base) de la ligne selectionnee dans la liste GCode et les donnees de cette ligne. ''' idx = self.__gcodeFileUi.selectionModel().selectedIndexes() return [idx[0].row(), self.__gcodeFileUiModel.data(idx[0])] def saveAs(self): fName = self.showFileSave() if fName[0] != "": self.sig_log.emit(logSeverity.info.value, self.tr("saveAs({})").format(fName[0])) self.saveFile(fName[0]) else: self.sig_log.emit(logSeverity.info.value, self.tr("saveAs() canceled!")) def showFileSave(self): ''' Affiche la boite de dialogue "Save as" ''' opt = QtWidgets.QFileDialog.Options() opt |= QtWidgets.QFileDialog.DontUseNativeDialog fName = QtWidgets.QFileDialog.getSaveFileName( None, self.tr("Save GCode file"), "", self.tr("GCode file (*.gcode *.ngc *.nc *.gc *.cnc)"), options=opt) return fName def saveFile(self, filePath: str = ""): if filePath == "": if self.__filePath == "": # Le nom du fichier n'est pas definit, il n'y a pas de fichier charge, donc, rien a sauvegarder ! return else: filePath = self.__filePath self.sig_log.emit(logSeverity.info.value, self.tr("Saving file: {}").format(filePath)) try: f = open(filePath, 'w') for I in range(self.__gcodeFileUiModel.rowCount()): idx = self.__gcodeFileUiModel.index(I, 0, QModelIndex()) if self.__gcodeFileUiModel.data(idx) != "": f.write(self.__gcodeFileUiModel.data(idx) + '\n') f.close() self.__filePath = filePath except Exception as e: self.sig_log.emit(logSeverity.error.value, self.tr("Save file error: {}").format(filePath)) self.sig_log.emit(logSeverity.error.value, str(e)) # Supprime les lignes vides dans la grille d'affichage self.delEmptyRow() # Reinit du flag fichier change self.__gcodeChanged = False def enQueue(self, com: grblCom, startLine: int = 0, endLine: int = -1): """ Envoi des lignes de startLine a endLine dans la file d'attente du grblCom """ if endLine == -1: endLine = self.__gcodeFileUiModel.rowCount() for I in range(startLine, endLine + 1): idx = self.__gcodeFileUiModel.index(I, 0, QModelIndex()) if self.__gcodeFileUiModel.data(idx) != "": com.gcodePush(self.__gcodeFileUiModel.data(idx)) com.gcodePush(CMD_GRBL_GET_GCODE_STATE, COM_FLAG_NO_OK) def delEmptyRow(self): """ Elimination des lignes GCode vides """ for I in reversed(range(self.__gcodeFileUiModel.rowCount())): # On commence par la fin pour pouvoir supprimer sans tout decaler pour la suite idx = self.__gcodeFileUiModel.index(I, 0, QModelIndex()) if self.__gcodeFileUiModel.data(idx) == "": self.__gcodeFileUiModel.removeRow(I) def deleteGCodeFileLine(self, num: int): self.__gcodeFileUiModel.removeRow(num) self.__gcodeChanged = True def insertGCodeFileLine(self, num: int): item = QStandardItem("") self.__gcodeFileUiModel.insertRow(num, item) def addGCodeFileLine(self, num: int): item = QStandardItem("") self.__gcodeFileUiModel.insertRow(num + 1, item) def showConfirmChangeLost(self): m = msgBox( title=self.tr("Save Changes"), text=self.tr("Do you want to save the changes before closing?"), info=self. tr("If you do not save, any changes made since opening or the last save will be lost." ), icon=msgIconList.Question, stdButton=msgButtonList.Save | msgButtonList.Cancel | msgButtonList.Discard, defButton=msgButtonList.Save, escButton=msgButtonList.Cancel) return (m.afficheMsg()) def closeFile(self): if self.__gcodeChanged: # GCode modifie, on demande confirmation Ret = self.showConfirmChangeLost() if Ret == msgButtonList.Save: if self.__filePath == "": filePath = self.showFileSave() if filePath == "": # Annulation de la boite de dialogue return False else: self.__filePath = filePath self.saveFile(self.__filePath) return True elif Ret == msgButtonList.Discard: # Fermer le fichier consiste en vider la fenetre GCode self.__gcodeFileUiModel.clear() self.__gcodeChanged = False self.__gcodeCharge = False return True else: # Ret == msgButtonList.Cancel: return False else: # GCode non modifie, on ferme sans confirmation # Fermer le fichier consiste en vider la fenetre GCode # et a supprimer le status GCode charge. self.__gcodeFileUiModel.clear() self.__gcodeChanged = False self.__gcodeCharge = False return True @pyqtSlot("QStandardItem*") def on_gcodeChanged(self, item): self.__gcodeChanged = True def gcodeChanged(self): return self.__gcodeChanged def setGcodeChanged(self, value: bool): self.__gcodeChanged = value
class Application(QMainWindow): def __init__(self, version, window=QMainWindow(), player=Player()): QMainWindow.__init__(self) self.ui = Ui_Main() self.window = window self.ui.setupUi(window) self.player = player self.version = version # Init Timer self.timer = QtCore.QTimer() self.timer.start(1000) # Update every second self.timer.timeout.connect(self.track_elapsed) # Button icons window_icon = QIcon() window_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__)) + "/images/window/icon.png"), QIcon.Normal, QIcon.Off) self.window.setWindowIcon(window_icon) self.play_icon = QIcon() self.play_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__)) + "/images/buttons/play.png"), QIcon.Normal, QIcon.Off) self.pause_icon = QIcon() self.pause_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__)) + "/images/buttons/pause.png"), QIcon.Normal, QIcon.Off) self.next_icon = QIcon() self.next_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__)) + "/images/buttons/next.png"), QIcon.Normal, QIcon.Off) self.prev_icon = QIcon() self.prev_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__)) + "/images/buttons/previous.png"), QIcon.Normal, QIcon.Off) self.stop_icon = QIcon() self.stop_icon.addPixmap(QPixmap(os.path.dirname(os.path.realpath(__file__)) + "/images/buttons/stop.png"), QIcon.Normal, QIcon.Off) # Set buttons self.ui.playpauseButton.setIcon(self.play_icon) self.ui.nextButton.setIcon(self.next_icon) self.ui.previousButton.setIcon(self.prev_icon) self.ui.stopButton.setIcon(self.stop_icon) # CheckBox for showing / hiding Expanded Lists self.ui.expandCheck.stateChanged.connect(self.lists) # And for showing / hiding video window self.ui.videoCheck.stateChanged.connect(self.video_window) # For dragging the slider self.was_it_playing = None self.ui.TrackSlider.sliderPressed.connect(self.slider_pressed) self.ui.TrackSlider.sliderReleased.connect(self.play_when_slider_released) self.ui.TrackSlider.sliderMoved.connect(self.player.change_item_pos) # Model to hold track list self.queueTrackListModel = QStandardItemModel(self.ui.trackList) self.ui.trackList.setModel(self.queueTrackListModel) self.recentTrackListModel = QStandardItemModel(self.ui.recentTracksList) self.ui.recentTracksList.setModel(self.recentTrackListModel) self.ui.trackList.doubleClicked.connect(self.choose_track_from_queue) self.ui.recentTracksList.doubleClicked.connect(self.choose_track_from_recent) self.ui.trackList.hide() # we start the list hidden self.ui.recentTracksList.hide() # likewise # Connect GUI buttons self.ui.playpauseButton.clicked.connect(self.play_track) # Play / Pause button self.ui.stopButton.clicked.connect(self.stop_track) # Stop button self.ui.nextButton.clicked.connect(self.next_track) # Next button self.ui.previousButton.clicked.connect(self.prev_track) # Next button self.ui.actionQuit.triggered.connect(sys.exit) # Quit from menu self.ui.actionOpen.triggered.connect(self.choose_track) # Open single item from menu self.ui.actionOpen_Several.triggered.connect(self.choose_tracks) # Open several items from menu self.ui.actionOpen_Directory.triggered.connect(self.choose_directory) # Open a directory from menu self.ui.actionAbout_LiMu.triggered.connect(self.about_dialog) # Keyboard shortcuts self.shortcut_next_track = QShortcut(QKeySequence("Right"), self.window) self.shortcut_next_track.activated.connect(self.next_track) self.shortcut_prev_track = QShortcut(QKeySequence("Left"), self.window) self.shortcut_prev_track.activated.connect(self.prev_track) self.shortcut_play_track = QShortcut(QKeySequence("Up"), self.window) self.shortcut_play_track.activated.connect(self.play_track) self.shortcut_stop_track = QShortcut(QKeySequence("Down"), self.window) self.shortcut_stop_track.activated.connect(self.stop_track) self.shortcut_open_folder = QShortcut(QKeySequence("Ctrl+O"), self.window) self.shortcut_open_folder.activated.connect(self.choose_directory) self.shortcut_open_track = QShortcut(QKeySequence("Ctrl+I"), self.window) self.shortcut_open_track.activated.connect(self.choose_track) self.shortcut_open_tracks = QShortcut(QKeySequence("Ctrl+L"), self.window) self.shortcut_open_tracks.activated.connect(self.choose_tracks) self.shortcut_quit = QShortcut(QKeySequence("Ctrl+Q"), self.window) self.shortcut_quit.activated.connect(sys.exit) # Starts expanded if set in settings.conf if config['Expanded'] is True: self.ui.expandCheck.nextCheckState() self.window.setMaximumSize(QSize(_expX, _expY)) self.window.setMinimumSize(QSize(_expX, _expY)) self.window.resize(_expX, _expY) self.ui.trackList.show() self.ui.recentTracksList.show() # Stuck Counter ( A BUG ) self.stuck_counter = 0 def lists(self): if self.ui.expandCheck.isChecked(): self.window.setMaximumSize(QSize(_expX, _expY)) self.window.setMinimumSize(QSize(_expX, _expY)) self.window.resize(_expX, _expY) self.ui.trackList.show() self.ui.recentTracksList.show() else: self.window.setMaximumSize(QSize(_norX, _norY)) self.window.setMinimumSize(QSize(_norX, _norY)) self.window.resize(_norX, _norY) self.ui.trackList.hide() self.ui.recentTracksList.hide() def video_window(self): self.check_video() if self.player.video.isEnabled(): if self.ui.videoCheck.isChecked(): self.player.video.show() else: self.player.video.hide() def check_video(self): if self.player.get_item() is not None: video = False for v in video_files: if self.player.get_item().lower().endswith(v): self.ui.videoCheck.setEnabled(True) video = True if video is False: self.ui.videoCheck.setChecked(False) self.ui.videoCheck.setEnabled(False) def slider_pressed(self): if self.player.status == "playing": self.play_track() self.was_it_playing = True else: self.was_it_playing = False def play_when_slider_released(self): if self.was_it_playing is True: self.play_track() def choose_track_from_queue(self, chosen): self.player.stop_item() if self.player.get_item() is not None: self.current_to_recent() location = chosen.data(1) self.player.set_item(location) print("loaded: " + self.player.get_item()) location = chosen.data(1) self.queueTrackListModel.removeRow(chosen.row()) self.meta_info(location, active=True) self.play_track() def choose_track_from_recent(self, chosen): self.player.stop_item() location = chosen.data(1) self.recentTrackListModel.removeRow(chosen.row()) if self.player.get_item() is not None: self.current_to_recent() self.player.set_item(location) self.play_track() self.meta_info(location, active=True) @pyqtSlot() def play_track(self): if self.player.get_item() is not None: self.player.play_item() self.video_window() print(self.player.status) if self.player.status == "paused": self.ui.playpauseButton.setIcon(self.play_icon) elif self.player.status == "playing": self.ui.playpauseButton.setIcon(self.pause_icon) else: print("No track to play") @pyqtSlot() def stop_track(self): if self.player.get_item() is not None: self.player.stop_item() print(self.player.status) self.ui.playpauseButton.setIcon(self.play_icon) @pyqtSlot() def next_track(self): error = "There's no track" try: self.current_to_recent() self.get_next_track() self.play_track() except AttributeError: print(error + " (" + AttributeError.__name__ + ")") except TypeError: print(error + " (" + TypeError.__name__ + ")") @pyqtSlot() def prev_track(self): previous_track = self.recentTrackListModel.takeItem(0) if previous_track is not None or previous_track is not "": try: location = previous_track.data(1) try: self.player.stop_item() print(self.player.get_item()) playing_track = self.player.get_item() playing_meta = self.meta_info(playing_track) item = QStandardItem(playing_track) item.setFlags(item.flags() & ~QtCore.Qt.ItemIsDropEnabled) # This is necessary to drag'n'drop within QueueList item.setText(playing_meta) item.setData(playing_track, 1) self.queueTrackListModel.insertRow(0, item) print("goes back one step..") except FileNotFoundError: print("no current track..") self.player.set_item(location) print("loaded: " + self.player.get_item()) self.meta_info(location, active=True) self.recentTrackListModel.removeRow(0) print(previous_track.data(0) + " taken back from recent.") self.play_track() except AttributeError: print("nope") elif previous_track is None or previous_track is "": print("there's no track - cannot go backwards") def current_to_recent(self): track = self.player.get_item() if track is not "": item = QStandardItem(track) track_meta = self.meta_info(track) item.setText(track_meta) item.setData(track, 1) self.recentTrackListModel.insertRow(0, item) @pyqtSlot() def choose_track(self, arg=False): if arg is not False: chosen = [arg] elif arg is False: chosen = QFileDialog.getOpenFileName(parent=self.window, filter="Media (*.mp3 *.ogg *.oga *.wav *.flac *.wma *.mkv *.mp4 *.avi *.mpg *.ogv)", directory=os.getenv('HOME'), caption="Open single track") if chosen[0] != "": if self.player.status != "stopped": self.player.stop_item() if self.player.get_item() is not None: self.current_to_recent() location = chosen[0] self.player.set_item(location) print("loaded: " + self.player.get_item()) self.meta_info(location, active=True) self.play_track() @pyqtSlot() def choose_tracks(self): chosen = QFileDialog.getOpenFileNames(parent=self.window, directory=os.getenv('HOME'), caption="Open one or more tracks") tracks = chosen[0] count = len(tracks) start_all = time.time() for track in tracks: is_audio = False is_video = False for a in audio_files: if track.lower().endswith(a): is_audio = True break for v in video_files: if track.lower().endswith(v): is_video = True break if is_audio: queue.put(track) # Adds it directly, bypassing threading (doesn't play nice) elif is_video: self.process_track(track) # The track wasn't a playable track at all! else: count -= 1 self.start_working(start_all, count) @pyqtSlot() def choose_directory(self, arg=False): dir_files = '' if arg is not False: directory = [arg][0] dir_files = os.listdir(directory) else: directory = QFileDialog.getExistingDirectory(directory=os.getenv('HOME'), caption="Open directory with tracks") if directory != '': dir_files = os.listdir(directory) count = len(dir_files) start_all = time.time() for track in dir_files: is_audio = False is_video = False for a in audio_files: if track.lower().endswith(a): is_audio = True break for v in video_files: if track.lower().endswith(v): is_video = True break if is_audio: fullpath = os.path.realpath(directory) + "/" + track queue.put(fullpath) # # Adds it directly, bypassing threading (doesn't play nice) elif is_video: fullpath = os.path.realpath(directory) + "/" + track self.process_track(fullpath) # Track was no track at all! else: count -= 1 self.start_working(start_all, count) def get_next_track(self): try: next_track = self.queueTrackListModel.takeItem(0) print("takes next track from queue..") location = next_track.data(1) self.player.set_item(location) print("loaded: " + self.player.get_item()) self.meta_info(location, active=True) self.queueTrackListModel.removeRow(0) print(next_track.data(0) + " removed from queue.") self.play_track() self.ui.playpauseButton.setIcon(self.pause_icon) except AttributeError: print("queue's empty.. I'll hang back for now") self.player.reset() self.ui.playpauseButton.setIcon(self.play_icon) def meta_info(self, location, active=False): taginfo = os.path.basename(location) try: tagger = read_tag(location) taginfo = tagger.artist + " - " + tagger.title + " (" + tagger.album + ")"# + " (" + tagger.date + ")" if active is True: if len(taginfo) > 54: taginfo = taginfo[:52] self.ui.TrackInformationText.setText(taginfo + "..") else: self.ui.TrackInformationText.setText(taginfo) except NameError: # If NoTagError couldn't import because of lack of stagger if active is True: self.ui.TrackInformationText.setText(os.path.basename(location)) except NoTagError: if active is True: self.ui.TrackInformationText.setText(os.path.basename(location)) return taginfo def track_elapsed(self): track = self.player.track_item_pos() if self.player.status is "playing": # Song finished if track[3] >= track[4]: if track[4] != 0: # test-fix for early track switching | booo print("finished playing song") self.current_to_recent() self.player.stop_item() self.get_next_track() # -||- but placeholder fix for 1sec left bug if track[3] == track[4] - 1: stuck = self.is_it() if stuck is True: print("finished playing song (IN AN UGLY WAY)") self.current_to_recent() self.player.stop_item() self.get_next_track() if track[4] != 0: self.ui.TrackElapsedText.setText("+" + track[0]) self.ui.TrackLengthText.setText(track[1]) self.ui.TrackLeftText.setText("-" + track[2]) self.ui.TrackSlider.setMaximum(track[4]) if self.player.status is not "paused": self.ui.TrackSlider.setValue(track[3]) def is_it(self): self.stuck_counter += 1 if self.stuck_counter == 3: self.stuck_counter = 0 return True else: return False def about_dialog(self): from PyQt5.QtWidgets import QDialog, QLabel, QWidget from PyQt5.QtCore import QRect d = QDialog(self.window) d.setWindowTitle("About LiMu") container = QWidget(d) container.setGeometry(QRect(0, 0, 200, 80)) intro = QLabel(container) intro.setText("the Liothe Music Player") made_by = QLabel(container) made_by.setText("\nCreated by: Liothe") version = QLabel(container) version.setText("\n\nVersion: " + self.version) d.show() def process_track(self, track): with lock: start_single = time.time() item = QStandardItem(track) item.setFlags(item.flags() & ~QtCore.Qt.ItemIsDropEnabled) # This is necessary to drag'n'drop within QueueList track_info = self.meta_info(track) item.setText(track_info) item.setData(track, 1) self.queueTrackListModel.appendRow(item) stop_single = time.time() - start_single print("queued:", os.path.basename(item.data(0)), "(" + str(stop_single.__round__(5)) + ")" + " --- " + threading.current_thread().name) if self.player.status is None: self.get_next_track() def start_working(self, start_time, count): for i in range(os.cpu_count()): threading.Thread(target=self.workerbee_do, daemon=True, name="workerbee " + str(i + 1)).start() stop_all = time.time() - start_time queue.join() with lock: print("Adding", str(count), "tracks took", str(stop_all.__round__(5)) + "seconds") def workerbee_do(self): while True: item = queue.get() self.process_track(item) queue.task_done()
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.setCentralWidget(self.ui.splitter) self.__ColCount = 6 #列数=6 self.itemModel = QStandardItemModel(5, self.__ColCount, self) # 数据模型,10行6列 self.selectionModel = QItemSelectionModel(self.itemModel) #Item选择模型 self.selectionModel.currentChanged.connect(self.do_curChanged) self.__lastColumnTitle = "测井取样" self.__lastColumnFlags = (Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) ##tableView设置 self.ui.tableView.setModel(self.itemModel) #设置数据模型 self.ui.tableView.setSelectionModel(self.selectionModel) #设置选择模型 oneOrMore = QAbstractItemView.ExtendedSelection self.ui.tableView.setSelectionMode(oneOrMore) #可多选 itemOrRow = QAbstractItemView.SelectItems self.ui.tableView.setSelectionBehavior(itemOrRow) #单元格选择 self.ui.tableView.verticalHeader().setDefaultSectionSize(22) #缺省行高 self.ui.tableView.setAlternatingRowColors(True) #交替行颜色 self.ui.tableView.setEnabled(False) #先禁用tableView self.__buildStatusBar() ## ==============自定义功能函数============ def __buildStatusBar(self): ##构建状态栏 self.LabCellPos = QLabel("当前单元格:", self) self.LabCellPos.setMinimumWidth(180) self.ui.statusBar.addWidget(self.LabCellPos) self.LabCellText = QLabel("单元格内容:", self) self.LabCellText.setMinimumWidth(150) self.ui.statusBar.addWidget(self.LabCellText) self.LabCurFile = QLabel("当前文件:", self) self.ui.statusBar.addPermanentWidget(self.LabCurFile) def __iniModelFromStringList(self, allLines): ##从字符串列表构建模型 rowCnt = len(allLines) #文本行数,第1行是标题 self.itemModel.setRowCount(rowCnt - 1) #实际数据行数 headerText = allLines[0].strip() #第1行是表头,去掉末尾的换行符 "\n" headerList = headerText.split("\t") #转换为字符串列表 self.itemModel.setHorizontalHeaderLabels(headerList) #设置表头标题 self.__lastColumnTitle = headerList[len(headerList) - 1] # 最后一列表头的标题,即“测井取样” lastColNo = self.__ColCount - 1 #最后一列的列号 for i in range(rowCnt - 1): lineText = allLines[i + 1].strip() #一行的文字,\t分隔 strList = lineText.split("\t") #分割为字符串列表 for j in range(self.__ColCount - 1): #不含最后一列 item = QStandardItem(strList[j]) self.itemModel.setItem(i, j, item) #设置模型的item item = QStandardItem(self.__lastColumnTitle) #最后一列 item.setFlags(self.__lastColumnFlags) item.setCheckable(True) if (strList[lastColNo] == "0"): item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Checked) self.itemModel.setItem(i, lastColNo, item) #设置最后一列的item def __setCellAlignment(self, align=Qt.AlignHCenter): if (not self.selectionModel.hasSelection()): #没有选择的项 return selectedIndex = self.selectionModel.selectedIndexes() #模型索引列表 count = len(selectedIndex) for i in range(count): index = selectedIndex[i] #获取其中的一个模型索引 item = self.itemModel.itemFromIndex(index) #获取一个单元格的项数据对象 item.setTextAlignment(align) #设置文字对齐方式 ## ==========由connectSlotsByName() 自动连接的槽函数================== @pyqtSlot() ##“打开文件” def on_actOpen_triggered(self): ## curPath=QDir.currentPath() #获取当前路径 curPath = os.getcwd() #获取当前路径 filename, flt = QFileDialog.getOpenFileName( self, "打开一个文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return self.LabCurFile.setText("当前文件:" + filename) self.ui.plainTextEdit.clear() aFile = open(filename, 'r') allLines = aFile.readlines() #读取所有行,list类型,每行末尾带有 \n aFile.close() for strLine in allLines: self.ui.plainTextEdit.appendPlainText(strLine.strip()) self.__iniModelFromStringList(allLines) self.ui.tableView.setEnabled(True) #tableView可用 self.ui.actAppend.setEnabled(True) #更新Actions的enable属性 self.ui.actInsert.setEnabled(True) self.ui.actDelete.setEnabled(True) self.ui.actSave.setEnabled(True) self.ui.actModelData.setEnabled(True) @pyqtSlot() ##保存文件 def on_actSave_triggered(self): ## curPath=QDir.currentPath() #获取当前路径 curPath = os.getcwd() #获取当前路径 filename, flt = QFileDialog.getSaveFileName( self, "保存文件", curPath, "井斜数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return self.on_actModelData_triggered() #更新数据到plainTextEdit aFile = open(filename, 'w') #以写方式打开 aFile.write(self.ui.plainTextEdit.toPlainText()) aFile.close() @pyqtSlot() ##在最后添加一行 def on_actAppend_triggered(self): itemlist = [] # QStandardItem 对象列表 for i in range(self.__ColCount - 1): #不包括最后一列 item = QStandardItem("0") itemlist.append(item) item = QStandardItem(self.__lastColumnTitle) #最后一列 item.setCheckable(True) item.setFlags(self.__lastColumnFlags) itemlist.append(item) self.itemModel.appendRow(itemlist) #添加一行 curIndex = self.itemModel.index(self.itemModel.rowCount() - 1, 0) self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() ##插入一行 def on_actInsert_triggered(self): itemlist = [] # QStandardItem 对象列表 for i in range(self.__ColCount - 1): #不包括最后一列 item = QStandardItem("0") itemlist.append(item) item = QStandardItem(self.__lastColumnTitle) #最后一列 item.setFlags(self.__lastColumnFlags) item.setCheckable(True) item.setCheckState(Qt.Checked) itemlist.append(item) curIndex = self.selectionModel.currentIndex() #获取当前选中项的模型索引 self.itemModel.insertRow(curIndex.row(), itemlist) #在当前行的前面插入一行 self.selectionModel.clearSelection() self.selectionModel.setCurrentIndex(curIndex, QItemSelectionModel.Select) @pyqtSlot() ##删除当前行 def on_actDelete_triggered(self): curIndex = self.selectionModel.currentIndex() #获取当前选择单元格的模型索引 self.itemModel.removeRow(curIndex.row()) #删除当前行 @pyqtSlot() ##左对齐 def on_actAlignLeft_triggered(self): self.__setCellAlignment(Qt.AlignLeft | Qt.AlignVCenter) @pyqtSlot() ##中间对齐 def on_actAlignCenter_triggered(self): self.__setCellAlignment(Qt.AlignHCenter | Qt.AlignVCenter) @pyqtSlot() ##右对齐 def on_actAlignRight_triggered(self): self.__setCellAlignment(Qt.AlignRight | Qt.AlignVCenter) @pyqtSlot(bool) ##字体Bold def on_actFontBold_triggered(self, checked): if (not self.selectionModel.hasSelection()): #没有选择的项 return selectedIndex = self.selectionModel.selectedIndexes() #模型索引列表 count = len(selectedIndex) for i in range(count): index = selectedIndex[i] #获取其中的一个模型索引 item = self.itemModel.itemFromIndex(index) #获取一个单元格的项数据对象 font = item.font() font.setBold(checked) item.setFont(font) @pyqtSlot() ##模型数据显示到plainTextEdit里 def on_actModelData_triggered(self): self.ui.plainTextEdit.clear() lineStr = "" for i in range(self.itemModel.columnCount() - 1): #表头,不含最后一列 item = self.itemModel.horizontalHeaderItem(i) lineStr = lineStr + item.text() + "\t" item = self.itemModel.horizontalHeaderItem(self.__ColCount - 1) #最后一列 lineStr = lineStr + item.text() #表头文字字符串 self.ui.plainTextEdit.appendPlainText(lineStr) for i in range(self.itemModel.rowCount()): lineStr = "" for j in range(self.itemModel.columnCount() - 1): #不包括最后一列 item = self.itemModel.item(i, j) lineStr = lineStr + item.text() + "\t" item = self.itemModel.item(i, self.__ColCount - 1) #最后一列 if (item.checkState() == Qt.Checked): lineStr = lineStr + "1" else: lineStr = lineStr + "0" self.ui.plainTextEdit.appendPlainText(lineStr) ## =============自定义槽函数=============================== def do_curChanged(self, current, previous): if (current != None): #当前模型索引有效 text = "当前单元格:%d行,%d列" % (current.row(), current.column()) self.LabCellPos.setText(text) item = self.itemModel.itemFromIndex(current) #从模型索引获得Item self.LabCellText.setText("单元格内容:" + item.text()) #显示item的文字内容 font = item.font() #获取item的字体 self.ui.actFontBold.setChecked(font.bold()) #更新actFontBold的check状态
def addMail2(self, model: QStandardItemModel, mailFrom, subject, date): model.insertRow(0) model.setData(model.index(1, self.FROM), mailFrom) model.setData(model.index(1, self.SUBJECT), subject) model.setData(model.index(1, self.DATE), date)
class App(QWidget): global tableWidget def __init__(self): super().__init__() self.title = 'Tensorflow CV Recognition' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) button = QPushButton('Open a folder', self) button.setToolTip('This is an example button') button.move(100, 70) button.clicked.connect(self.on_click) self.createTable() # Add box layout, add table to box layout and add box layout to widget self.layout = QVBoxLayout() self.layout.addWidget(button) self.layout.addWidget(self.tableWidget) self.setLayout(self.layout) self.show() def openFileNameDialog(self): #options = QFileDialog.Options() #options |= QFileDialog.DontUseNativeDialog #fileName = str(QFileDialog.getExistingDirectory(self, "Select Directory")) fileName = QFileDialog.getExistingDirectory(None, 'Select a folder:') '''fileName, _ = QFileDialog.getOpenFileName(self, "QFileDialog.getOpenFileName()", "", "All Files (*);;Python Files (*.py)", options=options)''' if fileName: print(fileName) #fileName = '/'.join(fileName[0].split("/")[:-1])+"/" print(fileName) main(fileName) def openFileNamesDialog(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog files, _ = QFileDialog.getOpenFileNames( self, "QFileDialog.getOpenFileNames()", "", "All Files (*);;Python Files (*.py)", options=options) if files: print(files) def createTable(self): # Create table self.tableWidget = QTableView(self) self.model = QStandardItemModel(50, 2, self) self.model.setHorizontalHeaderLabels(["Document Number", "Decision"]) self.tableWidget.setModel(self.model) self.tableWidget.update() #self.model.insertRow(0, [QStandardItem("1"), QStandardItem("2")]) #self.tableWidget.setColumnCount(2) #self.tableWidget.setRowCount(20) self.tableWidget.setColumnWidth(0, 295) self.tableWidget.setColumnWidth(1, 295) self.tableWidget.move(100, 100) self.tableWidget.setUpdatesEnabled(True) def insert(self, i, row): self.model.insertRow(i - 1, [QStandardItem(row[0]), QStandardItem(row[1])]) self.tableWidget.setModel(self.model) @pyqtSlot() def on_click(self): print('PyQt5 button click') self.openFileNameDialog()
class InvoiceList(MyTreeView): class Columns(IntEnum): DATE = 0 DESCRIPTION = 1 AMOUNT = 2 STATUS = 3 headers = { Columns.DATE: _('Date'), Columns.DESCRIPTION: _('Description'), Columns.AMOUNT: _('Amount'), Columns.STATUS: _('Status'), } filter_columns = [Columns.DATE, Columns.DESCRIPTION, Columns.AMOUNT] def __init__(self, parent): super().__init__(parent, self.create_menu, stretch_column=self.Columns.DESCRIPTION) self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.setSortingEnabled(True) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.update() def update_item(self, key, invoice: Invoice): model = self.std_model for row in range(0, model.rowCount()): item = model.item(row, 0) if item.data(ROLE_REQUEST_ID) == key: break else: return status_item = model.item(row, self.Columns.STATUS) status = self.parent.wallet.get_invoice_status(invoice) status_str = invoice.get_status_str(status) if self.parent.wallet.lnworker: log = self.parent.wallet.lnworker.logs.get(key) if log and status == PR_INFLIGHT: status_str += '... (%d)' % len(log) status_item.setText(status_str) status_item.setIcon(read_QIcon(pr_icons.get(status))) def update(self): # not calling maybe_defer_update() as it interferes with conditional-visibility self.proxy.setDynamicSortFilter( False) # temp. disable re-sorting after every change self.std_model.clear() self.update_headers(self.__class__.headers) for idx, item in enumerate(self.parent.wallet.get_unpaid_invoices()): key = self.parent.wallet.get_key_for_outgoing_invoice(item) if item.is_lightning(): icon_name = 'lightning.png' else: icon_name = 'bitcoin.png' if item.bip70: icon_name = 'seal.png' status = self.parent.wallet.get_invoice_status(item) status_str = item.get_status_str(status) message = item.message amount = item.get_amount_sat() timestamp = item.time or 0 date_str = format_time(timestamp) if timestamp else _('Unknown') amount_str = self.parent.format_amount(amount, whitespaces=True) labels = [date_str, message, amount_str, status_str] items = [QStandardItem(e) for e in labels] self.set_editability(items) items[self.Columns.DATE].setIcon(read_QIcon(icon_name)) items[self.Columns.STATUS].setIcon(read_QIcon( pr_icons.get(status))) items[self.Columns.DATE].setData(key, role=ROLE_REQUEST_ID) items[self.Columns.DATE].setData(item.type, role=ROLE_REQUEST_TYPE) items[self.Columns.DATE].setData(timestamp, role=ROLE_SORT_ORDER) self.std_model.insertRow(idx, items) self.filter() self.proxy.setDynamicSortFilter(True) # sort requests by date self.sortByColumn(self.Columns.DATE, Qt.DescendingOrder) # hide list if empty if self.parent.isVisible(): b = self.std_model.rowCount() > 0 self.setVisible(b) self.parent.invoices_label.setVisible(b) def create_menu(self, position): wallet = self.parent.wallet items = self.selected_in_column(0) if len(items) > 1: keys = [item.data(ROLE_REQUEST_ID) for item in items] invoices = [wallet.invoices.get(key) for key in keys] can_batch_pay = all([ i.type == PR_TYPE_ONCHAIN and wallet.get_invoice_status(i) == PR_UNPAID for i in invoices ]) menu = QMenu(self) if can_batch_pay: menu.addAction( _("Batch pay invoices") + "...", lambda: self.parent.pay_multiple_invoices(invoices)) menu.addAction(_("Delete invoices"), lambda: self.parent.delete_invoices(keys)) menu.exec_(self.viewport().mapToGlobal(position)) return idx = self.indexAt(position) item = self.item_from_index(idx) item_col0 = self.item_from_index( idx.sibling(idx.row(), self.Columns.DATE)) if not item or not item_col0: return key = item_col0.data(ROLE_REQUEST_ID) invoice = self.parent.wallet.get_invoice(key) menu = QMenu(self) self.add_copy_menu(menu, idx) if invoice.is_lightning(): menu.addAction(_("Details"), lambda: self.parent.show_lightning_invoice(invoice)) else: if len(invoice.outputs) == 1: menu.addAction( _("Copy Address"), lambda: self.parent.do_copy(invoice.get_address(), title='Garlicoin Address')) menu.addAction(_("Details"), lambda: self.parent.show_onchain_invoice(invoice)) status = wallet.get_invoice_status(invoice) if status == PR_UNPAID: menu.addAction( _("Pay") + "...", lambda: self.parent.do_pay_invoice(invoice)) if status == PR_FAILED: menu.addAction(_("Retry"), lambda: self.parent.do_pay_invoice(invoice)) if self.parent.wallet.lnworker: log = self.parent.wallet.lnworker.logs.get(key) if log: menu.addAction(_("View log"), lambda: self.show_log(key, log)) menu.addAction(_("Delete"), lambda: self.parent.delete_invoices([key])) menu.exec_(self.viewport().mapToGlobal(position)) def show_log(self, key, log: Sequence[HtlcLog]): d = WindowModalDialog(self, _("Payment log")) d.setMinimumWidth(600) vbox = QVBoxLayout(d) log_w = QTreeWidget() log_w.setHeaderLabels([_('Hops'), _('Channel ID'), _('Message')]) log_w.header().setSectionResizeMode(2, QHeaderView.Stretch) log_w.header().setSectionResizeMode(1, QHeaderView.ResizeToContents) for payment_attempt_log in log: route_str, chan_str, message = payment_attempt_log.formatted_tuple( ) x = QTreeWidgetItem([route_str, chan_str, message]) log_w.addTopLevelItem(x) vbox.addWidget(log_w) vbox.addLayout(Buttons(CloseButton(d))) d.exec_()
class SubtitleEditor(SubTab): def __init__(self, filePath, subtitleData, parent = None): name = os.path.split(filePath)[1] super(SubtitleEditor, self).__init__(name, parent) self.__initWidgets() self.__initContextMenu() self._settings = SubSettings() self._filePath = filePath self._movieFilePath = None self._subtitleData = subtitleData self.refreshSubtitles() # Some signals self._subtitleData.fileChanged.connect(self.fileChanged) self._subtitleData.subtitlesAdded.connect(self._subtitlesAdded) self._subtitleData.subtitlesRemoved.connect(self._subtitlesRemoved) self._subtitleData.subtitlesChanged.connect(self._subtitlesChanged) self._model.itemChanged.connect(self._subtitleEdited) self.customContextMenuRequested.connect(self.showContextMenu) def __initWidgets(self): minimalSizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) # List of subtitles subListDelegate = SubListItemDelegate() self._model = QStandardItemModel(0, 3, self) self._model.setHorizontalHeaderLabels([_("Begin"), _("End"), _("Subtitle")]) self._subList = QTableView(self) self._subList.setModel(self._model) self._subList.setItemDelegateForColumn(0, subListDelegate) self._subList.setItemDelegateForColumn(1, subListDelegate) self._subList.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) self._searchBar = SearchBar(self) self._searchBar.hide() # Top toolbar toolbar = QHBoxLayout() toolbar.setAlignment(Qt.AlignLeft) #toolbar.addWidget(someWidget....) toolbar.addStretch(1) # Main layout grid = QGridLayout() grid.setSpacing(10) grid.setContentsMargins(0, 3, 0, 0) grid.addLayout(toolbar, 0, 0, 1, 1) # stretch to the right grid.addWidget(self._subList, 1, 0) grid.addWidget(self._searchBar, 2, 0) self.setLayout(grid) def __initContextMenu(self): self._contextMenu = QMenu(self) self.setContextMenuPolicy(Qt.CustomContextMenu) af = ActionFactory(self) insertSub = af.create(title = _("&Insert subtitle"), icon = "list-add", connection = self.insertNewSubtitle) self._contextMenu.addAction(insertSub) insertSub = af.create(title = _("&Add subtitle"), icon = "list-add", connection = self.addNewSubtitle) self._contextMenu.addAction(insertSub) removeSub = af.create(title = _("&Remove subtitles"), icon = "list-remove", connection = self.removeSelectedSubtitles) self._contextMenu.addAction(removeSub) def _changeRowBackground(self, rowNo, bg): with DisableSignalling(self._model.itemChanged, self._subtitleEdited): for columnNo in range(self._model.columnCount()): item = self._model.item(rowNo, columnNo) item.setBackground(bg) def _changeItemData(self, item, val, role): with DisableSignalling(self._model.itemChanged, self._subtitleEdited): item.setData(val, role) def _handleIncorrectItem(self, item): with DisableSignalling(self._model.itemChanged, self._subtitleEdited): item.setData(False, CustomDataRoles.ErrorFlagRole) bg = item.background() rowNo = item.row() self._changeRowBackground(rowNo, Qt.red) QTimer.singleShot(600, lambda rowNo=rowNo, bg=bg: self._changeRowBackground(rowNo, bg)) def _subtitleEdited(self, item): modelIndex = item.index() column = modelIndex.column() subNo = modelIndex.row() errorFlag = item.data(CustomDataRoles.ErrorFlagRole) if errorFlag is True: self._handleIncorrectItem(item) else: # TODO: timeStart and timeEnd might be displayed in a frame format in a bright future. # Check it and create FrameTime properly in that case. # TODO: Maybe add column numbers to some kind of enum to avoid magic numbers? oldSubtitle = self.subtitles[subNo] newSubtitle = oldSubtitle.clone() if 0 == column: timeStart = item.data(CustomDataRoles.FrameTimeRole) newSubtitle.change(start = timeStart) elif 1 == column: timeEnd = item.data(CustomDataRoles.FrameTimeRole) newSubtitle.change(end = timeEnd) elif 2 == column: newSubtitle.change(text = item.text()) command = ChangeSubtitle(self.filePath, oldSubtitle, newSubtitle, subNo) self._subtitleData.execute(command) def _subtitlesAdded(self, path, subNos): if path != self.filePath: return subtitles = self.subtitles for subNo in subNos: row = createRow(subtitles[subNo]) self._model.insertRow(subNo, row) def _subtitlesRemoved(self, path, subNos): if path != self.filePath: return for subNo in subNos: self._model.removeRow(subNo) def _subtitlesChanged(self, path, subNos): if path != self.filePath: return for subNo in subNos: self.refreshSubtitle(subNo) def _createNewSubtitle(self, data, subNo): fps = data.fps # data is passed to avoid unnecessary copies minFrameTime = FrameTime(fps, frames = 1) # calculate correct minimum subtitle start time if subNo > 0: timeStart = data.subtitles[subNo - 1].end + minFrameTime else: timeStart = FrameTime(fps, frames = 0) # calculate correct maximum subtitle end time if subNo < data.subtitles.size(): try: timeEnd = data.subtitles[subNo].start - minFrameTime except SubException: timeEnd = FrameTime(fps, frames = 0) else: timeEnd = timeStart + FrameTime(fps, frames = 50) # add subtitle to DataModel sub = Subtitle(timeStart, timeEnd, "") command = AddSubtitle(self.filePath, subNo, sub) with DisableSignalling(self._subtitleData.subtitlesAdded, self._subtitlesAdded): self._subtitleData.execute(command) # create subtitle graphical representation in editor sub list row = createRow(sub) self._model.insertRow(subNo, row) index = self._model.index(subNo, 2) self._subList.clearSelection() self._subList.setCurrentIndex(index) self._subList.edit(index) def addNewSubtitle(self): data = self.data subNo = data.subtitles.size() indices = self._subList.selectedIndexes() if len(indices) > 0: rows = [index.row() for index in indices] subNo = max(rows) + 1 self._createNewSubtitle(data, subNo) def insertNewSubtitle(self): data = self.data subNo = 0 indices = self._subList.selectedIndexes() if len(indices) > 0: rows = [index.row() for index in indices] subNo = max(rows) self._createNewSubtitle(data, subNo) def removeSelectedSubtitles(self): indices = self._subList.selectedIndexes() if len(indices) > 0: rows = list(set([index.row() for index in indices])) command = RemoveSubtitles(self.filePath, rows) self._subtitleData.execute(command) if self._model.rowCount() > rows[-1]: self._subList.selectRow(rows[-1]) else: self._subList.selectRow(self._model.rowCount() - 1) def highlight(self): self._searchBar.show() self._searchBar.highlight() def showContextMenu(self): self._contextMenu.exec(QCursor.pos()) def changeInputEncoding(self, encoding): data = self._subtitleData.data(self.filePath) if encoding != data.inputEncoding: try: data.encode(encoding) except UnicodeDecodeError: message = QMessageBox( QMessageBox.Warning, _("Decoding error"), _("Cannot decode subtitles to '%s' encoding.\nPlease try different encoding.") % encoding, QMessageBox.Ok, self ) message.exec() except LookupError: message = QMessageBox(QMessageBox.Warning, _("Unknown encoding"), _("Unknown encoding: '%s'") % encoding, QMessageBox.Ok, self ) message.exec() else: # TODO: outputEncoding command = ChangeData(self.filePath, data, _("Input encoding: %s") % encoding) self._subtitleData.execute(command) def changeOutputEncoding(self, encoding): data = self._subtitleData.data(self.filePath) if encoding != data.outputEncoding: data.outputEncoding = encoding command = ChangeData(self.filePath, data, _("Output encoding: %s") % encoding) self._subtitleData.execute(command) def changeSubFormat(self, fmt): data = self._subtitleData.data(self.filePath) if data.outputFormat != fmt: data.outputFormat = fmt command = ChangeData(self.filePath, data) self._subtitleData.execute(command) def changeFps(self, fps): data = self.data if data.fps != fps: data.subtitles.changeFps(fps) data.fps = fps command = ChangeData(self.filePath, data, _("FPS: %s") % fps) self._subtitleData.execute(command) def changeVideoPath(self, path): data = self.data if data.videoPath != path: data.videoPath = path command = ChangeData(self.filePath, data, _("Video path: %s") % path) self._subtitleData.execute(command) def offset(self, seconds): data = self.data fps = data.subtitles.fps if fps is None: log.error(_("No FPS for '%s' (empty subtitles)." % self.filePath)) return ft = FrameTime(data.subtitles.fps, seconds=seconds) data.subtitles.offset(ft) command = ChangeData(self.filePath, data, _("Offset by: %s") % ft.toStr()) self._subtitleData.execute(command) def detectFps(self): data = self.data if data.videoPath is not None: fpsInfo = File.detectFpsFromMovie(data.videoPath) if data.videoPath != fpsInfo.videoPath or data.fps != fpsInfo.fps: data.videoPath = fpsInfo.videoPath data.subtitles.changeFps(fpsInfo.fps) data.fps = fpsInfo.fps command = ChangeData(self.filePath, data, _("Detected FPS: %s") % data.fps) self._subtitleData.execute(command) def fileChanged(self, filePath): if filePath == self._filePath: self.refreshSubtitles() def refreshSubtitle(self, subNo): sub = self.subtitles[subNo] self._model.removeRow(subNo) self._model.insertRow(subNo, createRow(sub)) def refreshSubtitles(self): self._model.removeRows(0, self._model.rowCount()) for sub in self.subtitles: self._model.appendRow(createRow(sub)) def updateTab(self): self.refreshSubtitles() def selectedSubtitles(self): rows = self.selectedRows() subtitleList = [self.subtitles[row] for row in rows] return subtitleList def selectedRows(self): indices = self._subList.selectedIndexes() # unique list rows = list(set([index.row() for index in indices])) rows.sort() return rows def selectRow(self, row): self._subList.selectRow(row) @property def filePath(self): return self._filePath @property def movieFilePath(self): return self._movieFilePath @property def data(self): return self._subtitleData.data(self.filePath) @property def subtitles(self): return self.data.subtitles @property def history(self): return self._subtitleData.history(self.filePath) @property def inputEncoding(self): return self.data.inputEncoding @property def outputEncoding(self): return self.data.outputEncoding @property def outputFormat(self): return self.data.outputFormat
class Interface(QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) qApp.setStyle(QStyleFactory.create("Fusion")) # Считывание данных из БД, таблицы 'teams' con = sqlite3.connect('FootballManager.db') cur = con.cursor() result = cur.execute("""SELECT * FROM teams""").fetchall() con.close() # Заполнение класса Team, извлеченными данными self.arrayOfTeams = [] for x in result: self.arrayOfTeams.append(Team(x[0], x[1], x[2])) # Создание списка сезонов(состоит из игр -> команд -> игроков), каждый прошедший сезон сохраняется в отдельном файле, как архив self.globalNumberSeason = 0 self.ligas = [Liga(self.arrayOfTeams[:16], self.globalNumberSeason)] self.model = QStandardItemModel() self.listView.setModel(self.model) self.listView.clicked.connect(self.onListView) self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers) # Создание модели для таблицы команд self.modelForTableTeams = ModelForTableTeams(self.ligas[-1]) self.filterModelForTableTeams = QSortFilterProxyModel() self.filterModelForTableTeams.setSourceModel(self.modelForTableTeams) self.tableViewForTeams.setModel(self.filterModelForTableTeams) self.tableViewForTeams.setSortingEnabled(False) #self.tableViewForTeams.sortByColumn(0, Qt.AscendingOrder) self.tableViewForTeams.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.tableViewForTeams.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) self.tableViewForTeams.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) self.tableViewForTeams.setFont(QFont("times", 12)) self.tableViewForTeams.clicked.connect(self.openGame) # Создание модели для таблицы лучших бомбардиров self.modelForTablePlayers = ModelForTablePlayers(self.ligas[-1].allPlayers, func=lambda x: (x.goals, x.name)) self.filterModelForTablePlayers = QSortFilterProxyModel() self.filterModelForTablePlayers.setSourceModel(self.modelForTablePlayers) self.tableViewForPlayers.setModel(self.filterModelForTablePlayers) self.tableViewForPlayers.setSortingEnabled(False) #self.tableViewForPlayers.sortByColumn(0, Qt.AscendingOrder) self.tableViewForPlayers.setFont(QFont("times", 16)) self.tableViewForPlayers.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.tableViewForPlayers.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) self.tableViewForPlayers.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) # Создание модели для таблицы лучших распасовщиков self.modelForTablePlayersPass = ModelForTablePlayersPass(self.ligas[-1].allPlayers, func=lambda x: (x.correctPass / (x.allPass * 100), x.name) if x.skillPass != 1 and x.allPass != 0 else (0, x.name)) self.filterModelForTablePlayersPass = QSortFilterProxyModel() self.filterModelForTablePlayersPass.setSourceModel(self.modelForTablePlayersPass) self.tableViewForPlayersPass.setModel(self.filterModelForTablePlayersPass) self.tableViewForPlayersPass.setSortingEnabled(False) #self.tableViewForPlayers.sortByColumn(0, Qt.AscendingOrder) self.tableViewForPlayersPass.setFont(QFont("times", 16)) self.tableViewForPlayersPass.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.tableViewForPlayersPass.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) self.tableViewForPlayersPass.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) # Обновление таблиц self.onlineTables() self.pushButton.clicked.connect(self.playOneTour) # Проигровка 1 тура матчей лиги def playOneTour(self): # Если текущий тур не ушёл за границы дозволенного, то продолжить увеличивать туры if self.ligas[self.globalNumberSeason].tourNow != (self.ligas[self.globalNumberSeason].countTeams - 1) * 2: # Сыграть тур self.ligas[self.globalNumberSeason].playTour() item = QStandardItem(f'Tур {self.ligas[self.globalNumberSeason].tourNow + 1}\n') self.model.appendRow(item) #for i in range(self.ligas[self.globalNumberSeason].tourNow * # self.ligas[self.globalNumberSeason].countTeams // 2, # (self.ligas[self.globalNumberSeason].tourNow + 1) * # self.ligas[self.globalNumberSeason].countTeams // 2): # self.textEdit.insertPlainText(self.ligas[self.globalNumberSeason].games[i].teams[0].name + ' ' + # str(self.ligas[self.globalNumberSeason].games[i].homeGoal) + ':' + # str(self.ligas[self.globalNumberSeason].games[i].guestGoal) + ' ' + # self.ligas[self.globalNumberSeason].games[i].teams[1].name + '\n') #self.textEdit.insertPlainText('\n') # self.textEdit.insertPlainText('-------------------------------------\n') # Обновление таблиц self.ligas[self.globalNumberSeason].tourNow += 1 self.onlineTables() else: with open(f'season{self.globalNumberSeason}.txt', 'w') as f: for i in range(self.modelForTableTeams.rowCount()): f.write(self.modelForTableTeams.teams[i].name + ' ' + str(self.modelForTableTeams.teams[i].points) + '\n') # Обнуляем все значения для нового сезона for i in range(len(self.ligas[self.globalNumberSeason].teams)): self.ligas[self.globalNumberSeason].teams[i].zeroingOfNewSeason() # Увеличиваем номер сезона на 1 self.globalNumberSeason += 1 # Создание нового сезона self.ligas.append(Liga(self.arrayOfTeams[:16], self.globalNumberSeason)) self.modelForTableTeams.newDatas(self.ligas[-1]) # Обновление таблиц self.onlineTables() self.model.clear() def onlineTables(self): # Обновление данных таблиц self.modelForTableTeams.oneSort() startIndex = self.modelForTableTeams.createIndex(0, 0) stopIndex = self.modelForTableTeams.createIndex(self.modelForTableTeams.rowCount(), self.modelForTableTeams.columnCount()) self.tableViewForTeams.dataChanged(startIndex, stopIndex) # Обновление данных таблиц self.modelForTablePlayers.newData() startIndex = self.modelForTablePlayers.createIndex(0, 0) stopIndex = self.modelForTablePlayers.createIndex(self.modelForTablePlayers.rowCount(), self.modelForTablePlayers.columnCount()) self.tableViewForPlayers.dataChanged(startIndex, stopIndex) # Обновление данных таблиц self.modelForTablePlayersPass.newData() startIndex = self.modelForTablePlayersPass.createIndex(0, 0) stopIndex = self.modelForTablePlayersPass.createIndex(self.modelForTablePlayersPass.rowCount(), self.modelForTablePlayersPass.columnCount()) self.tableViewForPlayersPass.dataChanged(startIndex, stopIndex) # Изменение таблицы команд под новые данные self.tableViewForTeams.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.tableViewForTeams.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) self.tableViewForTeams.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) # Изменение таблицы бомбардиров под новые данные self.tableViewForPlayers.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.tableViewForPlayers.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) self.tableViewForPlayers.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) # Изменение таблицы бомбардиров под новые данные self.tableViewForPlayersPass.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.tableViewForPlayersPass.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) self.tableViewForPlayersPass.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) def openGame(self, index): row = index.row() column = index.column() if 2 <= column < 18: if column - 2 != row: temp = self.modelForTableTeams.table_values.findGameForIds( [self.modelForTableTeams.teams[row].id, self.modelForTableTeams.teams[column - 2].id]) if temp: print(temp.teams[0].name + ' ' + str(temp.homeGoal) + ' ' + ':' + ' ' + str(temp.guestGoal) + ' ' + temp.teams[1].name) for i in range(2): for x in temp.structures[i]: print(temp.teams[i].players[x].name, temp.teams[i].players[x].physic) print() def onListView(self, index): row = index.row() stTemp2 = str(self.model.item(row).text()) stTempClick0 = str(stTemp2).split()[0] stTempClick1 = stTemp2.split()[1] if stTempClick0 == 'Tур': if row + 1 == self.model.rowCount(): for i in range(self.ligas[-1].countTeams // 2): team1 = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).teams[0].name result = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).returnResult() team2 = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).teams[1].name stTemp = f'{team1} {result} {team2}' item = QStandardItem(stTemp) self.model.insertRow(row + 1, item) else: stTemp3 = str(self.model.item(row + 1).text()) stTempClick2 = str(stTemp3).split()[0] if stTempClick2 == 'Tур': for i in range(self.ligas[-1].countTeams // 2): team1 = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).teams[0].name result = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).returnResult() team2 = self.ligas[-1].findGameForIds(self.ligas[-1].games[int(stTempClick1) - 1][i].ids).teams[1].name stTemp = f'{team1} {result} {team2}' item = QStandardItem(stTemp) self.model.insertRow(row + 1, item) else: j = 0 stTempClick4 = '' print(6) while stTempClick4 != 'Tур' and j + row + 1 < self.model.rowCount(): print(stTempClick4, j + row) j += 1 stTemp4 = str(self.model.item(j + row).text()) stTempClick4 = str(stTemp4).split()[0] if stTempClick4 != 'Tур': for i in range(j): self.model.removeRow(row + 1) else: for i in range(j - 1): self.model.removeRow(row + 1) else: if ':' in stTemp2: if row + 1 != self.model.rowCount(): temp1 = str(self.model.item(row + 1).text()) if ':' in temp1 or 'Tур' in temp1: temp = stTemp2.split(':') name1 = ' '.join(temp[0].split()[:-1]) name2 = ' '.join(temp[1].split()[1:]) game = self.ligas[-1].findGameForNames(name1, name2) if game: item = QStandardItem(game.returnSostav()) self.model.insertRow(row + 1, item) else: self.model.removeRow(row + 1) else: temp = stTemp2.split(':') name1 = ' '.join(temp[0].split()[:-1]) name2 = ' '.join(temp[1].split()[1:]) game = self.ligas[-1].findGameForNames(name1, name2) if game: item = QStandardItem(game.returnSostav()) self.model.insertRow(row + 1, item)
class Dialog_ui(QDialog, Ui_Dialog): """ Class documentation goes here. """ def __init__(self, parent=None): """ Constructor @param parent reference to the parent widgets @type QWidget """ super(Dialog_ui, self).__init__(parent) self.setupUi(self) self.ActionStart() def ActionStart(self): self.lineEdit_2.installEventFilter(self) self.lineEdit_3.installEventFilter(self) self.lineEdit_2.setContextMenuPolicy(Qt.NoContextMenu) self.lineEdit_3.setContextMenuPolicy(Qt.NoContextMenu) self.m_model = QStandardItemModel(0, 1, self) m_completer = QCompleter(self.m_model, self) self.lineEdit_7.setCompleter(m_completer) m_completer.activated[str].connect(self.onEmailChoosed) def onEmailChoosed(self, email): self.lineEdit_7.setText(email) def eventFilter(self, object, event): if object == self.lineEdit_2: if event.type() == QEvent.MouseMove or event.type( ) == QEvent.MouseButtonDblClick: return True elif event.type() == QEvent.KeyPress: key = QKeyEvent(event) if key.matches(QKeySequence.SelectAll) or key.matches( QKeySequence.Copy) or key.matches(QKeySequence.Paste): return True elif object == self.lineEdit_3: if event.type() == QEvent.MouseMove or event.type( ) == QEvent.MouseButtonDblClick: return True elif event.type() == QEvent.KeyPress: key = QKeyEvent(event) if key.matches(QKeySequence.SelectAll) or key.matches( QKeySequence.Copy) or key.matches(QKeySequence.Paste): return True return QDialog.eventFilter(self, object, event) @pyqtSlot() def on_lineEdit_editingFinished(self): """ Slot documentation goes here. """ # TODO: not implemented yet regex_user = '******' username = self.lineEdit.text() if len(username) > 0: self.lineEdit_6.clear() rruser = re.compile(regex_user) if rruser.match(username) is None: self.lineEdit_6.setText('用户名不符合要求!') else: self.lineEdit_6.setText('用户名未填写!') @pyqtSlot() def on_lineEdit_2_editingFinished(self): """ Slot documentation goes here. """ # TODO: not implemented yet # raise NotImplementedError regex_pwd = "^([A-Z]|[a-z]|[0-9]|[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“'。,、?]){6,16}$" self.pwd1 = self.lineEdit_2.GetPassword() if len(self.pwd1) > 0: self.lineEdit_6.clear() rrpwd = re.compile(regex_pwd) if rrpwd.match(self.pwd1) is None: self.lineEdit_6.setText('密码不符合要求!') else: self.lineEdit_6.setText('密码未填写!') @pyqtSlot() def on_lineEdit_3_editingFinished(self): """ Slot documentation goes here. """ # TODO: not implemented yet # raise NotImplementedError self.pwd2 = self.lineEdit_3.GetPassword() regex_pwd = "^([A-Z]|[a-z]|[0-9]|[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“'。,、?]){6,16}$" if len(self.pwd2) > 0: self.lineEdit_6.clear() rrpwd = re.compile(regex_pwd) if rrpwd.match(self.pwd2) is None: self.lineEdit_6.setText('密码不符合要求!') if self.pwd1 != self.pwd2: self.lineEdit_6.setText('两次密码不一致!') else: self.lineEdit_6.setText('密码未填写!') @pyqtSlot() def on_lineEdit_4_editingFinished(self): """ Slot documentation goes here. """ # TODO: not implemented yet # raise NotImplementedError regex_phone = '^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$' phone = self.lineEdit_4.text() if len(phone) > 0: self.lineEdit_6.clear() rr1 = re.compile(regex_phone) if rr1.match(phone) is None: self.lineEdit_6.setText('请填写正确的手机号!') else: self.lineEdit_6.setText('手机号码未填写!') @pyqtSlot() def on_lineEdit_7_editingFinished(self): """ Slot documentation goes here. """ # TODO: not implemented yet # raise NotImplementedError regex_mail = '^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$' email = self.lineEdit_7.text() if len(email) > 0: self.lineEdit_6.clear() rr1 = re.compile(regex_mail) if rr1.match(email) is None: self.lineEdit_6.setText('请填写正确的邮箱地址!') else: self.lineEdit_6.setText('邮箱地址未填写!') @pyqtSlot(str) def on_lineEdit_7_textChanged(self, text): if '@' in self.lineEdit_7.text(): return emaillist = [ "@163.com", "@qq.com", "@gmail.com", "@live.com", "@126.com", "@139.com" ] self.m_model.removeRows(0, self.m_model.rowCount()) for i in range(0, len(emaillist)): self.m_model.insertRow(0) self.m_model.setData(self.m_model.index(0, 0), text + emaillist[i])
class RequestList(MyTreeView): class Columns(IntEnum): DATE = 0 DESCRIPTION = 1 AMOUNT = 2 STATUS = 3 headers = { Columns.DATE: _('Date'), Columns.DESCRIPTION: _('Description'), Columns.AMOUNT: _('Amount'), Columns.STATUS: _('Status'), } filter_columns = [Columns.DATE, Columns.DESCRIPTION, Columns.AMOUNT] def __init__(self, parent): super().__init__(parent, self.create_menu, stretch_column=self.Columns.DESCRIPTION, editable_columns=[]) self.wallet = self.parent.wallet self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.setSortingEnabled(True) self.selectionModel().currentRowChanged.connect(self.item_changed) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.update() def select_key(self, key): for i in range(self.model().rowCount()): item = self.model().index(i, self.Columns.DATE) row_key = item.data(ROLE_KEY) if key == row_key: self.selectionModel().setCurrentIndex( item, QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows) break def item_changed(self, idx: Optional[QModelIndex]): if idx is None: self.parent.receive_payreq_e.setText('') self.parent.receive_address_e.setText('') return if not idx.isValid(): return # TODO use siblingAtColumn when min Qt version is >=5.11 item = self.item_from_index(idx.sibling(idx.row(), self.Columns.DATE)) key = item.data(ROLE_KEY) req = self.wallet.get_request(key) if req is None: self.update() return self.parent.receive_payreq_e.setText( self.parent.wallet.get_request_URI(req)) self.parent.receive_address_e.setText(req.get_address()) self.parent.receive_payreq_e.repaint() # macOS hack (similar to #4777) self.parent.receive_address_e.repaint( ) # macOS hack (similar to #4777) def clearSelection(self): super().clearSelection() self.selectionModel().clearCurrentIndex() def refresh_status(self): m = self.std_model for r in range(m.rowCount()): idx = m.index(r, self.Columns.STATUS) date_idx = idx.sibling(idx.row(), self.Columns.DATE) date_item = m.itemFromIndex(date_idx) status_item = m.itemFromIndex(idx) key = date_item.data(ROLE_KEY) req = self.wallet.get_request(key) if req: status = self.parent.wallet.get_request_status(key) status_str = req.get_status_str(status) status_item.setText(status_str) status_item.setIcon(read_QIcon(pr_icons.get(status))) def update(self): # not calling maybe_defer_update() as it interferes with conditional-visibility self.parent.update_receive_address_styling() self.proxy.setDynamicSortFilter( False) # temp. disable re-sorting after every change self.std_model.clear() self.update_headers(self.__class__.headers) for req in self.wallet.get_sorted_requests(): assert isinstance(req, OnchainInvoice) key = req.id status = self.parent.wallet.get_request_status(key) status_str = req.get_status_str(status) request_type = req.type timestamp = req.time amount = req.get_amount_sat() message = req.message date = format_time(timestamp) amount_str = self.parent.format_amount(amount) if amount else "" labels = [date, message, amount_str, status_str] assert isinstance(req, OnchainInvoice) key = req.get_address() icon = read_QIcon("firocoin.png") tooltip = 'onchain request' items = [QStandardItem(e) for e in labels] self.set_editability(items) items[self.Columns.DATE].setData(request_type, ROLE_REQUEST_TYPE) items[self.Columns.DATE].setData(key, ROLE_KEY) items[self.Columns.DATE].setData(timestamp, ROLE_SORT_ORDER) items[self.Columns.DATE].setIcon(icon) items[self.Columns.STATUS].setIcon(read_QIcon( pr_icons.get(status))) items[self.Columns.DATE].setToolTip(tooltip) self.std_model.insertRow(self.std_model.rowCount(), items) self.filter() self.proxy.setDynamicSortFilter(True) # sort requests by date self.sortByColumn(self.Columns.DATE, Qt.DescendingOrder) # hide list if empty if self.parent.isVisible(): b = self.std_model.rowCount() > 0 self.setVisible(b) self.parent.receive_requests_label.setVisible(b) if not b: # list got hidden, so selected item should also be cleared: self.item_changed(None) def create_menu(self, position): items = self.selected_in_column(0) if len(items) > 1: keys = [item.data(ROLE_KEY) for item in items] menu = QMenu(self) menu.addAction(_("Delete requests"), lambda: self.parent.delete_requests(keys)) menu.exec_(self.viewport().mapToGlobal(position)) return idx = self.indexAt(position) # TODO use siblingAtColumn when min Qt version is >=5.11 item = self.item_from_index(idx.sibling(idx.row(), self.Columns.DATE)) if not item: return key = item.data(ROLE_KEY) req = self.wallet.get_request(key) if req is None: self.update() return menu = QMenu(self) self.add_copy_menu(menu, idx) URI = self.wallet.get_request_URI(req) menu.addAction(_("Copy Request"), lambda: self.parent.do_copy(URI, title='Dash URI')) menu.addAction( _("Copy Address"), lambda: self.parent.do_copy(req.get_address(), title='Dash Address')) #if 'view_url' in req: # menu.addAction(_("View in web browser"), lambda: webopen(req['view_url'])) menu.addAction(_("Delete"), lambda: self.parent.delete_requests([key])) run_hook('receive_list_menu', menu, key) menu.exec_(self.viewport().mapToGlobal(position))
class ElfInfo(DwarfDialog): onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest') def __init__(self, parent=None, file_path=None): super().__init__(parent=parent) h_box = QHBoxLayout(self) self._ident_titles = [ 'EI_MAG0', 'EI_MAG1', 'EI_MAG2', 'EI_MAG3', 'EI_CLASS', 'EI_DATA', 'EI_VERSION', 'EI_OSABI', 'EI_ABIVERSION', 'EI_PAD' ] self.elf_info = DwarfListView(self) self.elf_info.setRootIsDecorated(True) self.elf_info.setExpandsOnDoubleClick(True) self.elf_info.setContextMenuPolicy(Qt.CustomContextMenu) self.elf_info.customContextMenuRequested.connect(self._on_context_menu) h_box.addWidget(self.elf_info) self._elf_info_mdl = QStandardItemModel(0, 2) self._elf_info_mdl.setHeaderData(0, Qt.Horizontal, 'Name') self._elf_info_mdl.setHeaderData(1, Qt.Horizontal, 'Value') self.elf_info.setModel(self._elf_info_mdl) self.elf_info.doubleClicked.connect(self._on_dblclicked) self.title = "ELF Info" self._elf_file_path = None self.setLayout(h_box) if file_path: self.set_elf_file(file_path) def set_elf_file(self, file_path): self._elf_file_path = file_path self.title = 'ELF Info for ' + file_path self._elf_info_mdl.insertRow( 0, [QStandardItem('File'), QStandardItem(file_path)]) def set_parsed_data(self, parsed_data): parent_item = self._elf_info_mdl.item(0) if 'endian' in parsed_data: parent_item.appendRow([ QStandardItem('Endian'), QStandardItem(parsed_data['endian']) ]) if 'is64bit' in parsed_data: txt = 'No' if parsed_data['is64bit']: txt = 'Yes' parent_item.appendRow([QStandardItem('64Bit'), QStandardItem(txt)]) if 'header' in parsed_data: elf_header = QStandardItem('ELF Header') parent_item.appendRow([elf_header]) for d in parsed_data['header']: if d == 'e_ident': ident_item = QStandardItem(d) elf_header.appendRow([ ident_item, QStandardItem(str(parsed_data['header'][d])) ]) a = 0 for i in parsed_data['header'][d]: if a >= len(self._ident_titles): a = len(self._ident_titles) - 1 ident_item.appendRow([ QStandardItem(self._ident_titles[a]), QStandardItem(str(i)) ]) a += 1 else: elf_header.appendRow([ QStandardItem(d), QStandardItem(hex(parsed_data['header'][d])) ]) if 'programheaders' in parsed_data: prog_headers_item = QStandardItem('Program Headers') parent_item.appendRow([prog_headers_item]) i = 1 for header in parsed_data['programheaders']: header_item = QStandardItem("%d" % i) prog_headers_item.appendRow([header_item]) i += 1 for d in header: header_item.appendRow( [QStandardItem(d), QStandardItem(hex(header[d]))]) if 'sectionheaders' in parsed_data: sect_headers = QStandardItem('Section Headers') parent_item.appendRow([sect_headers]) i = 1 for header in parsed_data['sectionheaders']: txt = header['name'] if not txt: txt = 'NULL' header_item = QStandardItem(txt) sect_headers.appendRow([header_item]) i += 1 for d in header: if d == 'name': continue elif d == 'data' and header[d]: data_item = QStandardItem('Data') header_item.appendRow(data_item) base = self.parent().dwarf.dwarf_api( 'findModule', self._elf_file_path)['base'] for ptr in header[d]: if int(ptr): va = hex(int(base, 16) + int(ptr)) fo = hex(int(ptr)) if self.elf_info.uppercase_hex: va = va.upper().replace('0X', '0x') fo = fo.upper().replace('0X', '0x') data_item.appendRow([ QStandardItem(va), QStandardItem('FileOffset: ' + fo) ]) else: header_item.appendRow( [QStandardItem(d), QStandardItem(hex(header[d]))]) self.elf_info.expandAll() self.elf_info.resizeColumnToContents(0) self.elf_info.resizeColumnToContents(1) self.setMinimumWidth( self.elf_info.columnWidth(0) + self.elf_info.columnWidth(1) + 50) self.setMinimumHeight(400) self.elf_info.collapseAll() self.elf_info.expandToDepth(1) def _on_dblclicked(self, model_index): if model_index.column() == 0 and model_index.data(): if model_index.data().startswith('0x'): self.onShowMemoryRequest.emit(model_index.data()) def _on_context_menu(self, pos): model_index = self.elf_info.indexAt(pos) if model_index.column() == 0 and model_index.data(): if model_index.data().startswith('0x'): context_menu = QMenu() context_menu.addAction( 'Add to Bookmarks', lambda: self.parent().bookmarks_panel.insert_bookmark( model_index.data(), 'init_array')) context_menu.addAction( 'Copy Address', lambda: utils.copy_hex_to_clipboard(model_index.data())) # show contextmenu glbl_pt = self.elf_info.mapToGlobal(pos) context_menu.exec_(glbl_pt)
class Win3(QWidget): def __init__(self): super(Win3, self).__init__() self.mypdf = MyPdf() self.init_ui() styleFile = './ui/style2.qss' qssStyle = CommonHelper.readQss(styleFile) self.setStyleSheet(qssStyle) def init_ui(self): self.button1 = QPushButton(self) self.button1.setText('返回') self.button1.setProperty("level", "1") # 设置数据层次结构,4行4列 self.model = QStandardItemModel(0, 2) # #设置水平方向四个头标签文本内容 self.model.setHorizontalHeaderLabels(['序号', '文件名称']) # 实例化表格视图,设置模型为自定义的模型 self.tableView = QTableView(self) self.tableView.setModel(self.model) self.tableView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) # 使表宽度自适应 self.tableView.horizontalHeader().setSectionResizeMode( 0, QHeaderView.ResizeToContents) # 第0列根据文字调节 self.tableView.verticalHeader().setVisible(False) # 隐藏列表头 self.tableView.setSelectionBehavior( QAbstractItemView.SelectRows) # 设置选中模式为选中行 self.tableView.setStyleSheet( "selection-background-color:rgb(91,155,213)") # 高亮显示选中的行 self.button11 = QPushButton(self) self.button11.setText('+') self.button12 = QPushButton(self) self.button12.setText('-') self.button13 = QPushButton(self) self.button13.setText('上移') self.button14 = QPushButton(self) self.button14.setText('下移') self.button11.setProperty("level", "2") self.button12.setProperty("level", "2") self.button13.setProperty("level", "2") self.button14.setProperty("level", "2") self.hbox = QHBoxLayout() self.hbox.addWidget(self.button11) self.hbox.addWidget(self.button12) self.hbox.addWidget(self.button13) self.hbox.addWidget(self.button14) self.button2 = QPushButton(self) self.button2.setText('合并PDF') self.button2.setProperty("level", "1") self.label1 = QLabel(self) self.label1.setText('输出文件名:') self.lineedit1 = QLineEdit(self) self.button3 = QPushButton(self) self.button3.setText('选择文件夹') self.button3.setProperty("level", "2") self.hbox2 = QHBoxLayout() self.hbox2.addWidget(self.label1) self.hbox2.addWidget(self.lineedit1) self.hbox2.addWidget(self.button3) self.vbox = QVBoxLayout() self.vbox.addWidget(self.tableView) self.vbox.addLayout(self.hbox) self.vbox.addLayout(self.hbox2) self.vbox.addWidget(self.button2) self.vbox.addWidget(self.button1) self.setLayout(self.vbox) self.button11.clicked.connect(self.button11_clicked) self.button12.clicked.connect(self.button12_clicked) self.button13.clicked.connect(self.button13_clicked) self.button14.clicked.connect(self.button14_clicked) self.button2.clicked.connect(self.button2_clicked) self.button3.clicked.connect(self.button3_clicked) def button11_clicked(self): '''添加文件''' self.mypdf.file_lists = QFileDialog.getOpenFileNames( self, "选择文件", "/", "PDF Files (*.pdf)")[0] # print(self.mypdf.file_lists) # print(range(len(self.mypdf.file_lists))) for i in range(len(self.mypdf.file_lists)): row = self.model.rowCount() self.model.insertRow(row) #插入一行 item = QStandardItem(str(row + 1)) self.model.setItem(row, 0, item) item = QStandardItem(self.mypdf.file_lists[i]) self.model.setItem(row, 1, item) def button12_clicked(self): '''删除选中的行''' row = self.tableView.currentIndex().row() self.model.removeRow(int(row)) def button13_clicked(self): '''向上移动行''' row = self.tableView.currentIndex().row() if row > 0: str1 = self.model.item(row, 1).text() str2 = self.model.item(row - 1, 1).text() self.model.setItem(row, 1, QStandardItem(str2)) self.model.setItem(row - 1, 1, QStandardItem(str1)) self.tableView.selectRow(row - 1) def button14_clicked(self): '''向下移动行''' maxrow = self.model.rowCount() - 1 row = self.tableView.currentIndex().row() if row < maxrow: str1 = self.model.item(row, 1).text() str2 = self.model.item(row + 1, 1).text() self.model.setItem(row, 1, QStandardItem(str2)) self.model.setItem(row + 1, 1, QStandardItem(str1)) self.tableView.selectRow(row + 1) def button2_clicked(self): file_lists = [] maxrow = self.model.rowCount() for row in range(maxrow): file_lists.append(self.model.item(row, 1).text()) print(file_lists) newfilename = self.lineedit1.text() self.mypdf.merge(file_lists=file_lists, new_filename=newfilename) def button3_clicked(self): path = QFileDialog.getExistingDirectory() new_filename = path + '/' + '新合并文件.PDF' self.lineedit1.setText(new_filename)
class CreateModel: def createPrologModel(self, prologView): listProlog = Prolog.getPrologList() for element in listProlog: if str(element.fullname).startswith("[pre"): listProlog.remove(element) self.prologModel = QStandardItemModel() self.prologModel.modelReset self.prologModel.setHorizontalHeaderItem(0, QStandardItem("Nome Corso")) self.prologModel.setHorizontalHeaderItem(1, QStandardItem("Nome Schematico")) self.prologModel.setHorizontalHeaderItem(2, QStandardItem("Docente")) self.prologModel.setHorizontalHeaderItem(3, QStandardItem("Numero Studenti")) self.prologModel.setHorizontalHeaderItem(4, QStandardItem("Corso / Anno")) self.prologModel.setHorizontalHeaderItem(5, QStandardItem("Numero Ore")) self.prologModel.setHorizontalHeaderItem(6, QStandardItem("Laboratorio")) self.prologModel.setHorizontalHeaderItem(7, QStandardItem("Numero Slot")) self.prologModel.setHorizontalHeaderItem(8, QStandardItem("Durata Slot")) self.prologModel.setHorizontalHeaderItem(9, QStandardItem("Tipo")) self.prologModel.setHorizontalHeaderItem(10, QStandardItem("Link")) self.prologModel.setHorizontalHeaderItem(11, QStandardItem("Commento")) for row in range(0, len(listProlog)): listCorsi = str(listProlog[row].seguitoda).replace("][", "],[") nomecorso = QStandardItem(str(listProlog[row].fullname)) shortName = QStandardItem(str(listProlog[row].nomecorso)) docente = QStandardItem(str(listProlog[row].docente)) numstudenti = QStandardItem(str(listProlog[row].numstudenti)) seguitoda = QStandardItem(str(listCorsi)) numore = QStandardItem(str(listProlog[row].numore)) lab = QStandardItem(str(listProlog[row].lab)) numslot = QStandardItem(str(listProlog[row].numslot)) if str(listProlog[row].slotdur) != "None": slotdur = QStandardItem(str(listProlog[row].slotdur)) else: slotdur = QStandardItem("_") type = QStandardItem(str(listProlog[row].type)) link = QStandardItem(str(listProlog[row].link)) prologView.setModel(self.prologModel) self.prologModel.insertRow(row) #imposto il background dei laboratori if listProlog[row].fullname == "[]" or "_lab" in str(listProlog[row].nomecorso) or "lab_" in str(listProlog[row].nomecorso): nomecorso.setBackground(QBrush(QColor(65, 205, 255, 200))) shortName.setBackground(QBrush(QColor(65, 205, 255, 200))) docente.setBackground(QBrush(QColor(65, 205, 255, 200))) numstudenti.setBackground(QBrush(QColor(65, 205, 255, 200))) seguitoda.setBackground(QBrush(QColor(65, 205, 255, 200))) numore.setBackground(QBrush(QColor(65, 205, 255, 200))) lab.setBackground(QBrush(QColor(65, 205, 255, 200))) numslot.setBackground(QBrush(QColor(65, 205, 255, 200))) slotdur.setBackground(QBrush(QColor(65, 205, 255, 200))) type.setBackground(QBrush(QColor(65, 205, 255, 200))) link.setBackground(QBrush(QColor(65, 205, 255, 200))) self.prologModel.setItem(row, 0, nomecorso) self.prologModel.setItem(row, 1, shortName) self.prologModel.setItem(row, 2, docente) self.prologModel.setItem(row, 3, numstudenti) self.prologModel.setItem(row, 4, seguitoda) self.prologModel.setItem(row, 5, numore) self.prologModel.setItem(row, 6, lab) self.prologModel.setItem(row, 7, numslot) self.prologModel.setItem(row, 8, slotdur) self.prologModel.setItem(row, 9, type) self.prologModel.setItem(row, 10, link) self.prologModel.setItem(row, 11, QStandardItem("Inserisci Commento...")) prologView.resizeColumnsToContents() return self.prologModel def createExcelModel(self, excelView): listCorsi = Compare.Compare().startCompare() listNewCorsi = Compare.Compare().getNewCorsi() for element in listNewCorsi: listCorsi.append(element) #messagebox per controllare i nuovi corsi if (len(listNewCorsi) > 0): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.resize(400, 400) msg.setText("Attenzione") msg.setInformativeText("Sono stati aggiunti dei corsi!") msg.setWindowTitle("Attenzione") toPrint = "" for element in listNewCorsi: toPrint = str(toPrint) + "*" + str(element.nomecorso) + "\n" msg.setDetailedText(toPrint) msg.exec_() try: self.tableModel = QStandardItemModel() self.tableModel.setHorizontalHeaderItem(0, QStandardItem("Nome Corso")) self.tableModel.setHorizontalHeaderItem(1, QStandardItem("Docente")) self.tableModel.setHorizontalHeaderItem(2, QStandardItem("Seguito Da")) self.tableModel.setHorizontalHeaderItem(3, QStandardItem("Anno")) self.tableModel.setHorizontalHeaderItem(4, QStandardItem("Numero Ore")) except AttributeError: print("uops") excelView.setModel(self.tableModel) for row in range(0, len(listCorsi)): nomecorso = QStandardItem(str(listCorsi[row].nomecorso)) docente = QStandardItem(str(listCorsi[row].docente)) seguitoda = QStandardItem(str(listCorsi[row].seguitoda)) anno = QStandardItem(str(listCorsi[row].anno)) numore = QStandardItem(str(listCorsi[row].numore)) docenteHint = QStandardItem(str(listCorsi[row].docenteHint)) numoreHint = QStandardItem(str(listCorsi[row].numOreHint)) self.tableModel.insertRow(row) #se sono corsi nuovi li evidenzio in verde if listCorsi[row].docente == "" and listCorsi[row].numore == "": nomecorso.setBackground(QBrush(QColor(0,255,85,200))) docente.setBackground(QBrush(QColor(0, 255, 85, 200))) seguitoda.setBackground(QBrush(QColor(0, 255, 85, 200))) numore.setBackground(QBrush(QColor(0, 255, 85, 200))) anno.setBackground(QBrush(QColor(0, 255, 85, 200))) docenteHint.setBackground(QBrush(QColor(0, 255, 85, 200))) numoreHint.setBackground(QBrush(QColor(0, 255, 85, 200))) self.tableModel.setItem(row, 0, nomecorso) if (str(listCorsi[row].docente)) == str(None) or str(listCorsi[row].docente) == "": docenteHint.setBackground(QBrush(QColor(255,0,0,100))) self.tableModel.setItem(row, 1, docenteHint) else: self.tableModel.setItem(row, 1, docente) self.tableModel.setItem(row, 2, seguitoda) self.tableModel.setItem(row, 3, anno) if (listCorsi[row].numore == None): numoreHint.setBackground(QBrush(QColor(255,0,0,100))) self.tableModel.setItem(row, 4, numoreHint) else: self.tableModel.setItem(row, 4, numore) excelView.resizeColumnsToContents() return self.tableModel