def connect_to_signal(signal: pyqtSignal, callbacks): if not callbacks: return if callable(callbacks): callbacks = [callbacks] for callback in callbacks: signal.connect(callback)
def _chunked_download( filename: str, response: HTTPResponse, size: int, progress_signal: pyqtSignal ) -> None: """ Downloads the zip file and emits progress. :param response: the HTTP response to download the file from :param size: the size of the download, in bytes; used for progress :param progress_signal: the PyQt signal with which to emit download progress """ if not size: size = 10 ** 6 * 44 with open(filename, "wb") as f: bytes_downloaded = 0 block_size = 1024 * 10 while True: buffer = response.read(block_size) if not buffer: break f.write(buffer) bytes_downloaded += block_size progress_signal.emit(bytes_downloaded / size * 100)
def connect(signal: pyqtSignal, callback: Callable): """ By default calling ``signal.connect(callback)`` will dispose of context information. Practically, this leads to single line tracebacks when ``signal.emit()`` is invoked. This is very hard to debug. This function wraps the ``connect()`` call to give you additional traceback information, if the callback does crash. :param signal: the signal to ``connect()`` to. :param callback: the callback to connect (will be called after ``signal.emit(...)``. """ # Step 1: At time of calling this function: get the stack frames. # We reconstruct the stack as a ``traceback`` object. source = None for frame in list(inspect.stack())[1:]: source = types.TracebackType(source, frame.frame, frame.index or 0, frame.lineno) # Step 2: construct a lightweight StackSummary object which does not contain # actual frames or locals, to avoid memory leak try: summary = traceback.StackSummary.extract(traceback.walk_tb(source), capture_locals=False) finally: del source # Step 3: Wrap the ``callback`` and inject our creation stack if an error occurs. # The BaseException instead of Exception is intentional: this makes sure interrupts of infinite loops show # the source callback stack for debugging. def trackback_wrapper(*args, **kwargs): try: callback(*args, **kwargs) except BaseException as exc: traceback_str = '\n' + ''.join(summary.format()) raise exc from CreationTraceback(traceback_str) try: setattr(callback, "tb_wrapper", trackback_wrapper) except AttributeError: # This is not a free function, but either an external library or a method bound to an instance. if not hasattr(callback, "tb_wrapper") and hasattr( callback, "__self__") and hasattr(callback, "__func__"): # methods are finicky: you can't set attributes on them. # Instead, we inject the handlers for each method in a dictionary on the instance. bound_obj = callback.__self__ if not hasattr(bound_obj, "tb_mapping"): setattr(bound_obj, "tb_mapping", {}) bound_obj.tb_mapping[ callback.__func__.__name__] = trackback_wrapper else: logging.warning( "Unable to hook up connect() info to %s. Probably a 'builtin_function_or_method'.", repr(callback)) # Step 3: Connect our wrapper to the signal. signal.connect(trackback_wrapper)
def task(signal: QtCore.pyqtSignal): """ 多线程任务函数 :param signal: Qt信号 :return: None """ while True: time.sleep(1) signal.emit(json.dumps(time.time()))
def _mock_download(progress_signal: pyqtSignal) -> None: """ Pretends to download a zip file. Used for testing when the zip file is already stored in the current working directory. """ counter = 0 while counter <= 100: progress_signal.emit(counter) counter += 1 time.sleep(2 / 100)
def buffered_send(stream: Iterable[object], signal: pyqtSignal, size=2000): buff = [] i = 0 for data in stream: buff.append(data) i += 1 if i == size: signal.emit(buff) i = 0 buff = [] if i > 0: signal.emit(buff)
def download_images(signal: pyqtSignal, core: LegendaryCore): if not os.path.isdir(IMAGE_DIR): os.makedirs(IMAGE_DIR) logger.info("Create Image dir") # Download Images for i, game in enumerate( sorted(core.get_game_list(), key=lambda x: x.app_title)): try: download_image(game) except json.decoder.JSONDecodeError: shutil.rmtree(f"{IMAGE_DIR}/{game.app_name}") download_image(game) signal.emit(i)
def disconnect(signal: pyqtSignal, callback: Callable): """ After using ``connect()`` to link a signal, use this function to disconnect from the given signal. This function will also work if the ``callback`` was connected directly with ``signal.connect()``. :param signal: the signal to ``disconnect()`` from. :param callback: the callback to connect (will be called after ``signal.emit(...)``. """ if hasattr(callback, 'tb_wrapper'): disconnectable = callback.tb_wrapper elif hasattr(callback, "__self__") and hasattr(callback, "__func__"): disconnectable = callback.__self__.tb_mapping[callback.__func__.__name__] else: disconnectable = callback signal.disconnect(disconnectable)
def __init__(self, conditions: List[SelectionCondition], control: QWidget, signal: pyqtSignal, action: Callable, activate_action: Callable = None, deactivate_action: Callable = None, model_change_handler: Callable = None): self.__conditions = conditions self.__control = control self.__action = action self.__activate_action = activate_action self.__deactivate_action = deactivate_action self.__model_change_handler = model_change_handler signal.connect(lambda *args: action(self._selection, *args)) self.update_selection([])
def __init__(self, settings: Settings, db: DB, on_create: Callable, on_date_click: Callable, tasks_changed_event: qtc.pyqtSignal, factory: TaskWidgetFactory): super().__init__() tasks_changed_event.connect(self._redraw_tasks) self._db = db self._factory = factory self._settings = settings main_layout = qtw.QVBoxLayout() self.setLayout(main_layout) self._current_date = date.today() self._date_button = qtw.QPushButton(clicked=on_date_click) font = self._date_button.font() font.setPixelSize(20) self._date_button.setFont(font) self._update_date_label() tasks_scroll_area = qtw.QScrollArea(widgetResizable=True) tasks_scroll_area_content = qtw.QWidget() tasks_scroll_area.setWidget(tasks_scroll_area_content) self._tasks_layout = qtw.QVBoxLayout(tasks_scroll_area_content) self._tasks_layout.setAlignment(qtc.Qt.AlignTop) self._prev_day_button = qtw.QPushButton( text=settings.PREVIOUS_DAY_BUTTON_TEXT, clicked=lambda: self._change_day(-1)) self._create_task_button = qtw.QPushButton( text=settings.CREATE_TASK_BUTTON_TEXT, clicked=on_create) self._next_day_button = qtw.QPushButton( text=settings.NEXT_DAY_BUTTON_TEXT, clicked=lambda: self._change_day(1)) buttons_layout = qtw.QHBoxLayout() buttons_layout.addWidget(self._prev_day_button) buttons_layout.addWidget(self._create_task_button) buttons_layout.addWidget(self._next_day_button) main_layout.addWidget(self._date_button) main_layout.addWidget(tasks_scroll_area) main_layout.addLayout(buttons_layout)
def is_connected(signal: pyqtSignal, slot: pyqtSlot) -> bool: """ Determine if a (bound) signal is connected to a slot. :param signal: signal (a return value from a call to pyqtSignal(...)) :param slot: slot (a method on a QObject, decorated with pyqtSlot) :return: True if connected, False otherwise """ try: signal.connect(slot, Qt.UniqueConnection) except TypeError as exc: assert str(exc) in ( 'connection is not unique', 'connect() failed between MyObj.sig_test[] and meth()') return True else: signal.disconnect(slot) return False
def chunked_download( filename: str, response: HTTPResponse, size: int = None, progress_signal: pyqtSignal = None, ) -> None: """ Downloads the zip file and emits progress. :param response: the HTTP response to download the file from :param size: the size of the download, in bytes; used for progress :param progress_signal: the PyQt signal with which to emit download progress """ if progress_signal is None: logging.warning(f"Progress signal is None.") if not size: length = response.headers.get("content-length") if length: length = int(length) logging.info(f"Download size is {length / 1024 ** 2:.1f}MB.") size = length else: size = 10**6 * 44 logging.warning(f"Guessing download size.") with open(filename, "wb") as f: bytes_downloaded = 0 block_size = 1024 * 10 while True: buffer = response.read(block_size) if not buffer: break f.write(buffer) bytes_downloaded += block_size if progress_signal: progress_signal.emit(bytes_downloaded / size * 100)
def _notifying_setter( self, attr_name: str, value: Any, on_set: pyqtSignal, on_unset: pyqtSignal, send_value: bool = False ): """ Utility for a setter that emits Qt signals when the attribute in question changes state. Parameters ---------- attr_name : identifies attribute to be set value : set attribute to this value on_set : emitted when the new value is not None on_unset : emitted when the new value is None send_value : if True, the new value will be included in the emitted signal """ setattr(self, attr_name, value) if value is None: on_unset.emit() else: if send_value: on_set.emit(value) else: on_set.emit()
def _obtain_transaction_data(self, format: TxSerialisationFormat, completion_signal: Optional[pyqtSignal], done_signal: pyqtSignal, completion_text: str) -> None: tx_data = self.tx.to_format(format) if not isinstance(tx_data, dict): # This is not ideal, but it covers both bases. if completion_signal is not None: completion_signal.emit(format, tx_data) done_signal.emit(format, tx_data) return steps = self._account.estimate_extend_serialised_transaction_steps( format, self.tx, tx_data) # The done callbacks should happen in the context of the GUI thread. def on_done(weakwindow: 'ElectrumWindow', future: concurrent.futures.Future) -> None: nonlocal format, done_signal try: data = future.result() except concurrent.futures.CancelledError: done_signal.emit(format, None) except Exception as exc: weakwindow.on_exception(exc) else: done_signal.emit(format, data) title = _("Obtaining transaction data") func = partial(self._obtain_transaction_data_worker, format, tx_data, completion_signal, completion_text) weakwindow = weakref.proxy(self._main_window) WaitingDialog(self, title, func, on_done=partial(on_done, weakwindow), progress_steps=steps, allow_cancel=True, close_delay=5)
def downloadFile(name, url, signals: pyqtSignal = None): headers = {'Proxy-Connection': 'keep-alive'} r = requests.get(url, stream=True, headers=headers) length = float(r.headers['content-length']) f = open(name, 'wb') count = 0 count_tmp = 0 time1 = time.time() for chunk in r.iter_content(chunk_size=512): if chunk: f.write(chunk) count += len(chunk) if time.time() - time1 > 1: p = count / length * 100 speed = (count - count_tmp) / 1024 / 1024 / 2 count_tmp = count Logger.println(f'已下载 {formatFloat(p)}% (下载速度:{formatFloat(speed)}M/s)') time1 = time.time() if signals: signals.emit(f'已下载 {formatFloat(p)}% (下载速度:{formatFloat(speed)}M/s)') signals.emit(f'已下载 {formatFloat(100)}%') f.close()
def download_images(signal: pyqtSignal, core: LegendaryCore): if not os.path.isdir(IMAGE_DIR): os.makedirs(IMAGE_DIR) logger.info("Create Image dir") # Download Images for i, game in enumerate( sorted(core.get_game_list(), key=lambda x: x.app_title)): if not os.path.isdir(f"{IMAGE_DIR}/" + game.app_name): os.mkdir(f"{IMAGE_DIR}/" + game.app_name) if not os.path.isfile(f"{IMAGE_DIR}/{game.app_name}/image.json"): json_data = {"DieselGameBoxTall": None, "DieselGameBoxLogo": None} else: json_data = json.load( open(f"{IMAGE_DIR}/{game.app_name}/image.json", "r")) for image in game.metadata["keyImages"]: if image["type"] == "DieselGameBoxTall" or image[ "type"] == "DieselGameBoxLogo": if json_data[ image["type"]] != image["md5"] or not os.path.isfile( f"{IMAGE_DIR}/{game.app_name}/{image['type']}.png" ): # Download json_data[image["type"]] = image["md5"] # os.remove(f"{IMAGE_DIR}/{game.app_name}/{image['type']}.png") json.dump( json_data, open(f"{IMAGE_DIR}/{game.app_name}/image.json", "w")) logger.info(f"Download Image for Game: {game.app_title}") url = image["url"] with open( f"{IMAGE_DIR}/{game.app_name}/{image['type']}.png", "wb") as f: f.write(requests.get(url).content) f.close() if not os.path.isfile(f'{IMAGE_DIR}/' + game.app_name + '/UninstalledArt.png'): if os.path.isfile(f'{IMAGE_DIR}/' + game.app_name + '/DieselGameBoxTall.png'): # finalArt = Image.open(f'{IMAGE_DIR}/' + game.app_name + '/DieselGameBoxTall.png') # finalArt.save(f'{IMAGE_DIR}/{game.app_name}/FinalArt.png') # And same with the grayscale one bg = Image.open( f"{IMAGE_DIR}/{game.app_name}/DieselGameBoxTall.png") uninstalledArt = bg.convert('L') uninstalledArt.save( f'{IMAGE_DIR}/{game.app_name}/UninstalledArt.png') elif os.path.isfile( f"{IMAGE_DIR}/{game.app_name}/DieselGameBoxLogo.png"): bg: Image.Image = Image.open( f"{IMAGE_DIR}/{game.app_name}/DieselGameBoxLogo.png") bg = bg.resize((int(bg.size[1] * 3 / 4), bg.size[1])) logo = Image.open( f'{IMAGE_DIR}/{game.app_name}/DieselGameBoxLogo.png' ).convert('RGBA') wpercent = ((bg.size[0] * (3 / 4)) / float(logo.size[0])) hsize = int((float(logo.size[1]) * float(wpercent))) logo = logo.resize((int(bg.size[0] * (3 / 4)), hsize), Image.ANTIALIAS) # Calculate where the image has to be placed pasteX = int((bg.size[0] - logo.size[0]) / 2) pasteY = int((bg.size[1] - logo.size[1]) / 2) # And finally copy the background and paste in the image # finalArt = bg.copy() # finalArt.paste(logo, (pasteX, pasteY), logo) # Write out the file # finalArt.save(f'{IMAGE_DIR}/' + game.app_name + '/FinalArt.png') logoCopy = logo.copy() logoCopy.putalpha(int(256 * 3 / 4)) logo.paste(logoCopy, logo) uninstalledArt = bg.copy() uninstalledArt.paste(logo, (pasteX, pasteY), logo) uninstalledArt = uninstalledArt.convert('L') uninstalledArt.save(f'{IMAGE_DIR}/' + game.app_name + '/UninstalledArt.png') else: logger.warning( f"File {IMAGE_DIR}/{game.app_name}/DieselGameBoxTall.png dowsn't exist" ) signal.emit(i)
def disconnect_lambda_slots(*, signal: pyqtSignal) -> None: # ignore first run - when no slots connected with contextlib.suppress(TypeError): signal.disconnect()
def __init__(self, text : str, newWindow_signal:QtCore.pyqtSignal, menuIndex : int, parent=None): super(Qtw.QPushButton, self).__init__(text, parent, cursor=QtCore.Qt.PointingHandCursor, toolTip='Change current editor', clicked=lambda: newWindow_signal.emit(menuIndex)) self.newWindow_signal = newWindow_signal self.menuIndex = menuIndex self.setSizePolicy(Qtw.QSizePolicy.Expanding, Qtw.QSizePolicy.Preferred) self.setObjectName('Custom_Window_Button') self.setStyleSheet(self.stylesheet)
def worker(widget: QtWidgets.QWidget, trigger: QtCore.pyqtSignal) -> None: while True: widget.refresh() trigger.emit(widget.render) if widget.delay > 0: time.sleep(widget.delay)