def setupView(self, webView: WebView): webPage = webView.page() webView.titleChanged.connect(self._title_changed) webView.urlChanged.connect(self._url_changed) webView.loadProgress.connect(self._load_progress) webPage.linkHovered.connect(self._link_hovered) webPage.iconChanged.connect(self._icon_changed) webView.webActionEnabledChanged.connect( self._web_action_enabled_changed) webView.loadStarted.connect(self._load_started) webPage.windowCloseRequested.connect(self._window_close_requested)
class WebPopupWindow(QWidget): def __init__(self, profile: QWebEngineProfile): super().__init__() self.m_addressBar = UrlLineEdit(self) self.m_view = WebView(self) self.setAttribute(Qt.WA_DeleteOnClose) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) layout = QVBoxLayout() # layout.setMargin(0) self.setLayout(layout) layout.addWidget(self.m_addressBar) layout.addWidget(self.m_view) self.m_view.setPage(WebPage(profile, self.m_view)) self.m_view.setFocus() self.m_addressBar.setReadOnly(True) self.m_addressBar.setFavIcon(QIcon(":defaulticon.png")) self.m_view.titleChanged.connect(self.setWindowTitle) self.m_view.urlChanged.connect(self.setUrl) self.m_view.page().iconChanged.connect(self.handleIconChanged) self.m_view.page().geometryChangeRequested.connect( self.handleGeometryChangeRequested) self.m_view.page().windowCloseRequested.connect(self.close) def view(self) -> QWebEngineView: return self.m_view def setUrl(self, url: QUrl): self.m_addressBar.setUrl(url) def handleGeometryChangeRequested(self, newGeometry: QRect): self.m_view.setMinimumSize(newGeometry.width(), newGeometry.height()) self.move(newGeometry.topLeft() - self.m_view.pos()) # let the layout do the magic self.resize(0, 0) self.show() def handleIconChanged(self, icon: QIcon): if icon.isNull(): self.m_addressBar.setFavIcon(QIcon(":defaulticon.png")) else: self.m_addressBar.setFavIcon(icon)
class Browser(QObject): comment_postdata_example = { 'ft_ent_identifier': '735272899920440', # ИД сообщения 'comment_text': 'Cool))', # Текст коментария 'source': '22', 'client_id': '1429632677205%3A3425397009', 'reply_fbid': '', 'parent_comment_id': '', 'rootid': 'u_ps_0_0_k', 'clp': '', 'attached_sticker_fbid': '0', 'attached_photo_fbid': '0', 'feed_context': '%7B%22fbfeed_context%22%3Atrue%2C%22location_type%22%3A36%2C%22is_starred%22%3Afalse%2C%22is_pinned_post%22%3Afalse%2C%22can_moderate_timeline_story%22%3Afalse%2C%22profile_id%22%3A308106089303792%2C%22outer_object_element_id%22%3A%22u_ps_0_0_0%22%2C%22object_element_id%22%3A%22u_ps_0_0_0%22%2C%22is_ad_preview%22%3Afalse%2C%22is_editable%22%3Afalse%7D', 'ft[tn]': '[]', 'ft[top_level_post_id]': '750869418360788', 'ft[fbfeed_location]': '36', 'nctr[_mod]': 'pagelet_timeline_main_column', 'av': '100009110845526', '__user': '******', '__a': '1', '__dyn': '', #пустой '__req': 'c', 'fb_dtsg': 'AQEkxiOYhtrJ', # инпут в теле документа 'ttstamp': '26581716611911872109105876676', '__rev': '1713404', } def __init__(self, parent): super().__init__(parent) self.set_url('http://google.ru') conn = QNetworkAccessManager() self.conn = conn self.r = QNetworkRequest() self.r.attribute(QNetworkRequest.CookieSaveControlAttribute, QVariant(True)) # self.r.setHeader(QNetworkRequest.ContentTypeHeader, "application/x-www-form-urlencoded") # self.r.setRawHeader("Referer", "http://www.facebook.com/") # self.r.setRawHeader("Host", "www.facebook.com") self.cj = QNetworkCookieJar() conn.setCookieJar(self.cj) conn.createRequest = self._create_request self.wv = WebView() self.wv.show() self.wv.page().setNetworkAccessManager(conn) # self.wv.auth() self.loop = QEventLoop() pass def _create_request(self, operation, request, data): # print(data) reply = QNetworkAccessManager.createRequest(self.conn, operation, request, data) self.conn.new_reply = reply self.wv_reply = reply return reply def set_url(self, url): if isinstance(url, QByteArray): self.url = QUrl().fromEncoded(url) else: self.url = QUrl(url) def send_request(self, post=None, data={}): loop = QEventLoop() self.r.setUrl(self.url) if post: encoded_data = self._urlencode_post_data(data) pprint(encoded_data) self.reply_post = self.conn.post(self.r, encoded_data) self.reply_post.downloadProgress.connect(self.prepare_responce) else: self.reply = self.conn.get(self.r) self.reply.finished.connect(self.prepare_responce) # return \ loop.exec() def prepare_responce(self): # self.check_redirect() self.responce = self.reply_post.readAll()#.data().decode('utf-8') pprint(self.responce) sys.exit() def check_redirect(self): print(self.url) a = self.reply.rawHeader('Location') if len(a) > 0: self.set_url(a) self.send_request() else: self.loop.exit() def test(self): self.wv.auth('https://www.facebook.com/freelanceuidesignerdeveloper') self.wv.authentication.connect(self.webview_login) def _urlencode_post_data(self, post_data): post_params = [] for (key, value) in post_data.items(): print(key, value) post_params.append(key+'='+value) return '&'.join(post_params) def webview_login(self): text_page = self.wv.page().mainFrame().toHtml() data = { 'ft_ent_identifier': '735272899920440', 'comment_text': 'amazing', 'source': '22', 'client_id': '1429632677205%3A3425397009', 'reply_fbid': '', 'parent_comment_id': '', 'rootid': 'u_ps_0_0_o', 'clp': '', 'attached_sticker_fbid': '0', 'attached_photo_fbid': '0', 'feed_context': '%7B%22fbfeed_context%22%3Atrue%2C%22location_type%22%3A36%2C%22is_starred%22%3Afalse%2C%22is_pinned_post%22%3Afalse%2C%22can_moderate_timeline_story%22%3Afalse%2C%22profile_id%22%3A308106089303792%2C%22outer_object_element_id%22%3A%22u_ps_0_0_0%22%2C%22object_element_id%22%3A%22u_ps_0_0_0%22%2C%22is_ad_preview%22%3Afalse%2C%22is_editable%22%3Afalse%7D', 'ft[tn]': '[]', 'ft[top_level_post_id]': '', 'ft[fbfeed_location]': '36', 'nctr[_mod]': 'pagelet_timeline_main_column', 'av': '100009110845526', '__user': '******', '__a': '1', '__dyn': '', #пустой '__req': 'c', 'fb_dtsg': 'AQEkxiOYhtrJ', # инпут в теле документа 'ttstamp': '26581716611911872109105876676', '__rev': '1713404', } dtsg_index = text_page.find('"token":"AQ') data['fb_dtsg'] = text_page[dtsg_index+9:dtsg_index+21] data['ttstamp'] = self.ttstamp_gen(data['fb_dtsg']) data['ft_ent_identifier'] = '849713745045784' # self.get_post_id(post_object) data['comment_text'] = random_number.choice(config.comments_list) pprint(data['comment_text']) # data['av'] = data['__user'] = from_user # self.applyMetaData() self.url = QUrl('https://www.facebook.com/ajax/ufi/add_comment.php') self.send_request(True, data) sys.exit() def applyMetaData(self): print('applyMetaData') raw_header = { 'Host': 'www.facebook.com', 'User-Agent': ' Mozilla/5.0 (X11; Linux x86_64; rv:37.0) Gecko/20100101 Firefox/37.0', 'Accept': ' text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': ' en-US,en;q=0.5', 'Content-Type': ' application/x-www-form-urlencoded; charset=UTF-8', 'Referer': ' https://www.facebook.com/SoftProposal?fref=nf', } for (key, header) in raw_header.items(): self.r.setRawHeader(key, header) @staticmethod def ttstamp_gen(fb_dtsg): u = '' for v in fb_dtsg: u += str(ord(v)) return '2'+u @staticmethod def get_post_id(post): if post.object_id: return post.object_id else: str = post.id.split('_') if len(str) > 1: return str[0] else: post.id
class Window(QDialog): Move = 0b0000 ResizeTop = 0b0001 ResizeRight = 0b0010 ResizeBottom = 0b0100 ResizeLeft = 0b1000 onshow = pyqtSignal() onhide = pyqtSignal() onfocus = pyqtSignal() onblur = pyqtSignal() onclose = pyqtSignal() onmove = pyqtSignal(int, int, int, int) onresize = pyqtSignal(int, int, int, int) onstatechange = pyqtSignal() onmouseenter = pyqtSignal() onmouseleave = pyqtSignal() def __init__(self, parent = None, url = '', width = None, height = None, isDialog = False): super(Window, self).__init__(parent if isDialog else None) assets.windows.append(self) if width is None: width = assets.manifest['width'] if height is None: height = assets.manifest['height'] windowFlags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint if isDialog: windowFlags |= Qt.Dialog else: windowFlags |= Qt.CustomizeWindowHint self.dragParams = {'type': 0, 'x': 0, 'y': 0, 'size': 5, 'margin': 0, 'draging': False} self.webView = WebView(self, url) self.api = API(self) self.parent = parent self.resize(width, height) self.setMouseTracking(True) self.setWindowFlags(windowFlags) self.setWindowTitle('Hybrid App Engine') self.setAttribute(Qt.WA_QuitOnClose, True) self.setAttribute(Qt.WA_DeleteOnClose, True) self.setAttribute(Qt.WA_TranslucentBackground, True) self.setVisible(assets.manifest['visible']) self.setResizable(assets.manifest['resizable']) self.setFrameless(assets.manifest['frameless']) self.setWindowIcon(QIcon(assets.manifest['icon'])) self.setTransBackground(assets.manifest['transBackground']) # Methods def setWindowFlags(self, windowFlags): visible = self.isVisible() super(Window, self).setWindowFlags(windowFlags) if visible: self.show() def testWindowFlags(self, windowFlags): return self.windowFlags() & windowFlags def getCursorType(self, x, y): width = self.width() height = self.height() size = self.dragParams['size'] margin = self.dragParams['margin'] isResizableX = self.isResizableX() isResizableY = self.isResizableY() cursorType = Window.Move if x >= margin and x <= width - margin and y >= margin and y <= height - margin: if y <= size + margin and isResizableY: cursorType |= Window.ResizeTop elif y >= height - margin - size and isResizableY: cursorType |= Window.ResizeBottom if x <= size + margin and isResizableX: cursorType |= Window.ResizeLeft elif x >= width - margin - size and isResizableX: cursorType |= Window.ResizeRight return cursorType # Slots # 获取父窗口 @pyqtSlot(result = QObject) def opener(self): return self.parent # 任务栏闪烁 @pyqtSlot() @pyqtSlot(int) def alert(self, msec = 0): QApplication.alert(self, msec) # 执行简单的JS @pyqtSlot(str, result = QObject) def eval(self, javaScript): obj = QObject(self) obj.setObjectName('evalResult') obj.setProperty('result', self.webView.eval(javaScript)) print(dir(self.onstatechange)) return obj # 截图 @pyqtSlot(result = str) @pyqtSlot(bool, result = str) @pyqtSlot(bool, str, result = bool) def capture(self, fullScreen = False, filename = ''): if fullScreen: image = QApplication.primaryScreen().grabWindow(0) else: image = QImage(self.webView.mainFrame.contentsSize(), QImage.Format_ARGB32) painter = QPainter(image) self.webView.mainFrame.render(painter) painter.end() if filename: return image.save(filename) else: data = QByteArray() buffer = QBuffer(data) buffer.open(QBuffer.WriteOnly) image.save(buffer, 'PNG') return bytes(data.toBase64()).decode() # 打开开发者工具 @pyqtSlot() def showInspector(self): self.webView.page().showInspector() # 关闭开发者工具 @pyqtSlot() def hideInspector(self): self.webView.page().hideInspector() # 搜索文本 @pyqtSlot(str, result = bool) def findText(self, text): return self.webView.page().findText(text) # 设置窗口图标 @pyqtSlot(str) def setIcon(self, icon): if isinstance(icon, str): icon = QIcon(self.api.normUrl(icon)) self.setWindowIcon(icon) # 设置内容是否已被修改(标题中需要有[*]标志) @pyqtSlot(bool) def setModified(self, modified): self.setWindowModified(modified) # 获取内容是否已被修改 @pyqtSlot(result = bool) def isModified(self): return self.isWindowModified() # 设置是否模态 @pyqtSlot(bool) def setModal(self, modal): super(Window, self).setModal(modal) # 获取是否模态 @pyqtSlot(result = bool) def isModal(self): return super(Window, self).isModal() # 设置是否在任务栏中显示 @pyqtSlot(bool) def setShowInTaskbar(self, showInTaskbar): if showInTaskbar: self.setWindowFlags(self.windowFlags() & ~ Qt.Tool) else: self.setWindowFlags(self.windowFlags() | Qt.Tool) # 获取是否在任务栏中显示 @pyqtSlot(result = bool) def isShowInTaskbar(self): return self.testWindowFlags(Qt.Tool) # 设置窗口是否置顶 @pyqtSlot(bool) def setStaysOnTop(self, staysOnTop): if staysOnTop: self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) else: self.setWindowFlags(self.windowFlags() & ~ Qt.WindowStaysOnTopHint) # 获取窗口是否置顶 @pyqtSlot(result = bool) def isStaysOnTop(self): return self.testWindowFlags(Qt.WindowStaysOnTopHint) # 设置是否显示系统边框 @pyqtSlot(bool) def setFrameless(self, frameless): if frameless: self.setWindowFlags(self.windowFlags() & ~ Qt.CustomizeWindowHint & ~ Qt.WindowTitleHint | Qt.FramelessWindowHint) else: self.setWindowFlags(self.windowFlags() & ~ Qt.FramelessWindowHint | Qt.CustomizeWindowHint | Qt.WindowTitleHint) # 获取是否显示系统边框 @pyqtSlot(result = bool) def isFrameless(self): return self.testWindowFlags(Qt.FramelessWindowHint) # 设置是否背景透明 @pyqtSlot(bool) def setTransBackground(self, transBackground): palette = self.palette() if transBackground: palette.setBrush(QPalette.Base, Qt.transparent) else: palette.setBrush(QPalette.Base, Qt.white) self.setPalette(palette) # 获取是否背景透明 @pyqtSlot(result = bool) def isTransBackground(self): palette = self.palette() return palette.brush(QPalette.Base) == Qt.transparent # 设置是否鼠标事件穿透 @pyqtSlot(bool) def setTransMouseEvent(self, transMouseEvent): self.setAttribute(Qt.WA_TransparentForMouseEvents, transMouseEvent) self.setWindowFlags(self.windowFlags() | Qt.WindowTitleHint) # 获取是否是否鼠标事件穿透 @pyqtSlot(result = bool) def isTransMouseEvent(self): return self.testAttribute(Qt.WA_TransparentForMouseEvents) # 设置窗口不透明度 @pyqtSlot(float) def setOpacity(self, opacity): self.setWindowOpacity(opacity) # 获取窗口不透明度 @pyqtSlot(result = float) def getOpacity(self): return self.windowOpacity() # 设置尺寸是否可调整 @pyqtSlot(bool) def setResizable(self, resizable): if resizable: self.setMinimumSize(5, 5) self.setMaximumSize(0xFFFFFF, 0xFFFFFF) else: self.setFixedSize(self.width(), self.height()) # 获取尺寸是否可调整 @pyqtSlot(result = bool) def isResizable(self): return self.minimumSize() != self.maximumSize() # 设置宽度是否可调整 @pyqtSlot(bool) def setResizableX(self, resizableX): if resizableX: self.setMinimumWidth(5) self.setMaximumWidth(0xFFFFFF) else: self.setFixedWidth(self.width()) # 获取宽度是否可调整 @pyqtSlot(result = bool) def isResizableX(self): return self.minimumWidth() != self.maximumWidth() # 设置高度是否可调整 @pyqtSlot(bool) def setResizableY(self, resizableY): if resizableY: self.setMinimumHeight(5) self.setMaximumHeight(0xFFFFFF) else: self.setFixedHeight(self.height()) # 获取高度是否可调整 @pyqtSlot(result = bool) def isResizableY(self): return self.minimumHeight() != self.maximumHeight() # 设置是否可最小化 @pyqtSlot(bool) def setMinimizable(self, minimizable): if minimizable: self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint) else: self.setWindowFlags(self.windowFlags() & ~ Qt.WindowMinimizeButtonHint) # 获取是否可最小化 @pyqtSlot(result = bool) def isMinimizable(self): return self.testWindowFlags(Qt.WindowMinimizeButtonHint) # 设置是否可最大化 @pyqtSlot(bool) def setMaximizable(self, maximizable): if maximizable: self.setWindowFlags(self.windowFlags() | Qt.WindowMaximizeButtonHint) else: self.setWindowFlags(self.windowFlags() & ~ Qt.WindowMaximizeButtonHint) # 获取是否可最大化 @pyqtSlot(result = bool) def isMaximizable(self): return self.testWindowFlags(Qt.WindowMaximizeButtonHint) # 设置是否可关闭 @pyqtSlot(bool) def setClosable(self, closable): if closable: self.setWindowFlags(self.windowFlags() | Qt.WindowCloseButtonHint) else: self.setWindowFlags(self.windowFlags() & ~ Qt.WindowCloseButtonHint) # 获取是否可关闭 @pyqtSlot(result = bool) def isClosable(self): return self.testWindowFlags(Qt.WindowCloseButtonHint) # 获取是否已最小化 @pyqtSlot(result = bool) def isMinimized(self): return super(Window, self).isMinimized() # 获取是否已最大化 @pyqtSlot(result = bool) def isMaximized(self): return super(Window, self).isMaximized() # 获取是否已最大化 @pyqtSlot(result = bool) def isFullScreen(self): return super(Window, self).isFullScreen() # 最小化 @pyqtSlot() def minimize(self): if self.isMinimizable(): self.showMinimized() # 还原 @pyqtSlot() def normalize(self): self.showNormal() # 最大化 @pyqtSlot() def maximize(self): if self.isMaximizable(): self.showMaximized() # 全屏 @pyqtSlot() def showFullScreen(self): super(Window, self).showFullScreen() # 设置窗口坐标 @pyqtSlot(int, int) def setPos(self, x, y): self.move(x, y) # 设置窗口尺寸 @pyqtSlot(int, int) def setSize(self, width, height): self.resize(width, height) # 设置窗口最小尺寸 @pyqtSlot(int, int) def setMinSize(self, width, height): self.setMinimumSize(width, height) # 设置窗口最大尺寸 @pyqtSlot(int, int) def setMaxSize(self, width, height): self.setMaximumSize(width, height) # 设置尺寸控制大小 @pyqtSlot(int) def setResizerSize(self, size): self.dragParams['size'] = size # 获取尺寸控制大小 @pyqtSlot(result = int) def getResizerSize(self): return self.dragParams['size'] # 设置尺寸控制边距 @pyqtSlot(int) def setResizerMargin(self, margin): self.dragParams['margin'] = margin # 获取尺寸控制边距 @pyqtSlot(result = int) def getResizerMargin(self): return self.dragParams['margin'] # 是否正在拖动 @pyqtSlot(result = bool) def isDraging(self): return self.dragParams['draging'] # 开始拖动 @pyqtSlot() def dragStart(self): self.dragParams['draging'] = True # 结束拖动 @pyqtSlot() def dragStop(self): self.dragParams['type'] = Window.Move self.dragParams['draging'] = False # 窗口获取焦点 @pyqtSlot() def activate(self): self.activateWindow() # 窗口是否已获得焦点 @pyqtSlot(result = bool) def isActive(self): return self.isActiveWindow() # 设置窗口可用状态 @pyqtSlot(bool) def setEnabled(self, enabled): super(Window, self).setEnabled(enabled) # 窗口是否可用 @pyqtSlot(result = bool) def isEnabled(self): return super(Window, self).isEnabled() # 设置窗口可见状态 @pyqtSlot(result = bool) def setVisible(self, visible): super(Window, self).setVisible(visible) # 窗口是否显示 @pyqtSlot(result = bool) def isVisible(self): return super(Window, self).isVisible() # 显示窗口 @pyqtSlot() def show(self): super(Window, self).show() # 隐藏窗口 @pyqtSlot() def hide(self): super(Window, self).hide() # 关闭窗口 @pyqtSlot() def close(self): super(Window, self).close() # Events def keyPressEvent(self, event): if(event.key() == Qt.Key_Escape): event.ignore() def mousePressEvent(self, event): self.dragParams['x'] = event.x() self.dragParams['y'] = event.y() self.dragParams['globalX'] = event.globalX() self.dragParams['globalY'] = event.globalY() self.dragParams['width'] = self.width() self.dragParams['height'] = self.height() if self.dragParams['type'] != Window.Move and self.isFrameless() and not self.isMaximized() and not self.isFullScreen(): self.dragStart() def mouseReleaseEvent(self, event): self.dragStop() def mouseMoveEvent(self, event): if self.isFrameless() and not self.isMaximized() and not self.isFullScreen(): # 判断鼠标类型 cursorType = self.dragParams['type'] if not self.dragParams['draging']: cursorType = self.dragParams['type'] = self.getCursorType(event.x(), event.y()) # 设置鼠标形状 if cursorType in (Window.ResizeTop, Window.ResizeBottom): self.webView.setCursor(Qt.SizeVerCursor) elif cursorType in (Window.ResizeLeft, Window.ResizeRight): self.webView.setCursor(Qt.SizeHorCursor) elif cursorType in (Window.ResizeTop | Window.ResizeRight, Window.ResizeLeft | Window.ResizeBottom): self.webView.setCursor(Qt.SizeBDiagCursor) elif cursorType in (Window.ResizeTop | Window.ResizeLeft, Window.ResizeRight | Window.ResizeBottom): self.webView.setCursor(Qt.SizeFDiagCursor) elif self.dragParams['draging']: self.webView.setCursor(Qt.ArrowCursor) # 判断窗口拖动 dragType = self.dragParams['type'] if self.dragParams['draging'] and not self.isMaximized() and not self.isFullScreen(): x = self.x() y = self.y() width = self.width() height = self.height() if dragType == Window.Move: x = event.globalX() - self.dragParams['x'] y = event.globalY() - self.dragParams['y'] elif self.isFrameless(): if dragType & Window.ResizeTop == Window.ResizeTop: y = event.globalY() - self.dragParams['margin'] height = self.dragParams['height'] + self.dragParams['globalY'] - event.globalY() elif dragType & Window.ResizeBottom == Window.ResizeBottom: height = self.dragParams['height'] - self.dragParams['globalY'] + event.globalY() if dragType & Window.ResizeLeft == Window.ResizeLeft: x = event.globalX() - self.dragParams['margin'] width = self.dragParams['width'] + self.dragParams['globalX'] - event.globalX() elif dragType & Window.ResizeRight == Window.ResizeRight: width = self.dragParams['width'] - self.dragParams['globalX'] + event.globalX() else: return if width < self.minimumWidth(): width = self.minimumWidth() elif width > self.maximumWidth(): width = self.maximumWidth() if height < self.minimumHeight(): height = self.minimumHeight() elif height > self.maximumHeight(): height = self.maximumHeight() self.setGeometry(x, y, width, height) def changeEvent(self, event): if event.type() == QEvent.ActivationChange: if self.isActiveWindow(): self.onfocus.emit() else: self.onblur.emit() elif event.type() == QEvent.WindowStateChange: self.onstatechange.emit() def resizeEvent(self, event): size = event.size() oldSize = event.oldSize() self.onresize.emit(size.width(), size.height(), oldSize.width(), oldSize.height()) self.webView.resize(super(Window, self).size()) def moveEvent(self, event): pos = event.pos() oldPos = event.oldPos() self.onmove.emit(pos.x(), pos.y(), oldPos.x(), oldPos.y()) def enterEvent(self, event): self.onmouseenter.emit() def leaveEvent(self, event): self.onmouseleave.emit() def showEvent(self, event): self.onshow.emit() def hideEvent(self, event): self.onhide.emit() def closeEvent(self, event): self.onclose.emit() if self.isClosable(): self.webView.close() assets.windows = [i for i in assets.windows if i != self] event.accept() else: event.ignore()