PySide6 ์น๋ทฐ์์ ๋งํฌ๊ฐ ์ ์ด๋ฆด ๋?
ํ์ด์ฌ์ผ๋ก ๋ฐ์คํฌํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ๋, ์น ์ฝํ ์ธ ๋ฅผ ํ์ํ๊ธฐ ์ํด QWebEngineView๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ๊ทธ๋ฌ๋ ๋งํฌ ํด๋ฆญ ์ ์๋ฌด ๋ฐ์์ด ์๊ฑฐ๋, ํ์ ์ด ์ด๋ฆฌ์ง ์์ผ๋ฉฐ, ์๋์ ๊ฐ์ ๊ฒฝ๊ณ ๋ฉ์์ง๋ฅผ ๋ง์ฃผํ๊ฒ ๋ ์ ์์ต๋๋ค.
RuntimeWarning: Invalid return value in function
'QWebEnginePage.createWindow', expected PySide6.QtWebEngineCore.QWebEnginePage,
got PySide6.QtWebEngineWidgets.QWebEngineView.
๊ฒ๋ณด๊ธฐ์ ๋จ์ํ ๊ฒฝ๊ณ ์ฒ๋ผ ๋ณด์ด์ง๋ง, ์ด ๋ฌธ์ ๋ ์น๋ทฐ์ ํต์ฌ ๊ธฐ๋ฅ์ ๋ฌด๋ ฅํ์ํฌ ์ ์๋ ์ฌ๊ฐํ ๋ฌธ์ ์ ๋๋ค. ์ด ๊ธ์์๋ ์ค๋ฅ์ ์์ธ๋ถํฐ ํด๊ฒฐ์ฑ ๊น์ง, ์ฝ๊ฒ ๋ฐ๋ผํ ์ ์๋๋ก ๋จ๊ณ๋ณ๋ก ์ค๋ช ํฉ๋๋ค.
ํ์ด์ฌ ๋ฐ์คํฌํ ์ฑ์์ ํ์ ์ด ์ ๋ ๋
1. ๋ฌธ์ ์ง๋จ: ์ ์ด๋ฐ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊น?
1.1 ์ค๋ฅ ๋ฉ์์ง ํด์
์ค๋ฅ ๋ฉ์์ง ์์ฝ
createWindow() ํจ์์์ ๋ฐํ๋ ๊ฐ์ฒด ํ์ ์ด ์๋ชป๋์์ต๋๋ค.
QWebEnginePage๋ฅผ ๋ฐํํด์ผ ํ๋๋ฐ, ์ค์๋ก QWebEngineView๋ฅผ ๋ฐํํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด ์ฐจ์ด๋ฅผ ์ดํดํ๋ ๊ฒ์ด ๋งค์ฐ ์ค์ํฉ๋๋ค.
1.2 ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ๋ํ ์ํฉ
- <a href="..." target="_blank"> ๋งํฌ ํด๋ฆญ ์
- JavaScript window.open() ํธ์ถ ์
- HTML ํ์ ์ฐฝ ์์ฑ ์๋
1.3 ์ด ์ค๋ฅ๊ฐ ๋ฌด์์ด ์ด์
- ๋๋ฒ๊น ์ด ์ด๋ ต๋ค: ํ๋ก๊ทธ๋จ์ ๋ฉ์ถ์ง ์๊ณ ์กฐ์ฉํ ์ด์ ๋์์ ํฉ๋๋ค.
- ๊ธฐ๋ฅ ์ ํ: ์ ์ฐฝ์ด ์๋ ํ์ฌ ์ฐฝ์์ ๋งํฌ๊ฐ ์ด๋ฆฝ๋๋ค.
- ํ๋ซํผ ๊ฐ ๋ถ์ผ์น: ์ด์์ฒด์ ์ ๋ฐ๋ผ ์ฆ์์ด ๋ค๋ฅด๊ฒ ๋ํ๋ ์ ์์ต๋๋ค.
2. ๊ทผ๋ณธ ์์ธ: Qt์ ๊ตฌ์กฐ ์ดํดํ๊ธฐ
2.1 QWebEngine์ 3๋ ์์
QWebEngineView | ๋ธ๋ผ์ฐ์ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๋ ์์ ฏ |
QWebEnginePage | ํ์ด์ง ๋์, ํ์ ์ฒ๋ฆฌ ๋ฑ ํต์ฌ ๊ธฐ๋ฅ ๋ด๋น |
QWebEngineProfile |
ํ์ ์ฒ๋ฆฌ๋ QWebEnginePage๊ฐ ๋ด๋นํ๋ฉฐ, createWindow()๋ ๋ฐ๋์ QWebEnginePage ๊ฐ์ฒด๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค.
2.2 ํ์ ๋ถ์ผ์น๊ฐ ๋ฐ์ํ๋ ์ด์
- ์ฌ์ฉ์๊ฐ ์ ์ฐฝ ์์ฒญ (target="_blank" ๋๋ JS)
- Qt๊ฐ ๋ด๋ถ์ ์ผ๋ก createWindow() ํธ์ถ
- ๋ฐํ๊ฐ์ด ์๋ชป๋๋ฉด ๊ฒฝ๊ณ ๋ฐ์ + ๋์ ์คํจ
3. ํด๊ฒฐ ๋ฐฉ๋ฒ: ์ฌ๋ฐ๋ฅธ ํ์ด์ง ๋ฐํํ๊ธฐ
3.1 ์ปค์คํ ํ์ด์ง ํด๋์ค ๊ตฌํ
from PySide6.QtWebEngineCore import QWebEnginePage
class SafeWebEnginePage(QWebEnginePage):
def __init__(self, profile, parent_view):
super().__init__(profile, parent_view)
self.parent_view = parent_view
def createWindow(self, type):
new_page = SafeWebEnginePage(self.profile(), self.parent_view)
self.parent_view.setPage(new_page)
return new_page # ๋ฐ๋์ QWebEnginePage ๋ฐํ
3.2 ์น๋ทฐ์ ์ ์ฉํ๊ธฐ
profile = QWebEngineProfile("MyProfile", self)
webpage = SafeWebEnginePage(profile, self.webview)
self.webview.setPage(webpage)
3.3 ํ์ ํ์ฉ ๋ฐ ์ด๋ฒคํธ ์ฒ๋ฆฌ
from PySide6.QtWebEngineWidgets import QWebEngineSettings
settings = self.webview.settings()
settings.setAttribute(QWebEngineSettings.JavascriptCanOpenWindows, True)
webpage.windowCloseRequested.connect(self.handle_window_close)
4. ์ค์ ์์
import sys
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWebEngineCore import QWebEnginePage, QWebEngineProfile
class SafeWebEnginePage(QWebEnginePage):
def __init__(self, profile, parent_view):
super().__init__(profile, parent_view)
self.parent_view = parent_view
def createWindow(self, type):
new_page = SafeWebEnginePage(self.profile(), self.parent_view)
self.parent_view.setPage(new_page)
return new_page
class BrowserWindow(QMainWindow):
def __init__(self):
super().__init__()
self.webview = QWebEngineView()
self.setCentralWidget(self.webview)
profile = QWebEngineProfile("Default", self)
webpage = SafeWebEnginePage(profile, self.webview)
self.webview.setPage(webpage)
self.webview.setUrl("https://example.com")
app = QApplication(sys.argv)
window = BrowserWindow()
window.show()
sys.exit(app.exec())
ํ ์คํธ HTML ์ฝ๋
<a href="https://python.org" target="_blank">์ ์ ๋งํฌ</a>
<button onclick="window.open('https://qt.io', '_blank')">JS ํ์
</button>
<a href="https://google.com" target="newwin">์ด๋ฆ ์ง์ ์ฐฝ</a>
5. ๋ฌธ์ ์๋ฐฉ์ ์ํ ์ฌ๋ก
ํ์ ์ผ๊ด์ฑ ์ ์ง
๋ฐํ๊ฐ์ ๋ฐ๋์ QWebEnginePage ์ฌ์ผ ํฉ๋๋ค.
if isinstance(new_page, QWebEnginePage):
self.parent_view.setPage(new_page)
์ฐธ์กฐ ์ํ ๋ฐฉ์ง
def __del__(self):
self.parent_view = None
์์ธ ์ฒ๋ฆฌ ์ถ๊ฐ
def createWindow(self, type):
try:
# ์ ์ ์ฒ๋ฆฌ
except Exception as e:
print(f"์ฐฝ ์์ฑ ์ค๋ฅ: {e}")
return super().createWindow(type)
์๋ํ๋ ์ค ๋ธ๋ก๊ทธ ์ด์ ์๋ํ ํ๋ก๊ทธ๋จ ๊ณต์ ์๊ฐ ์ ์ฝ๊ณผ ์ต์ ํ ํ
๋ธ๋ก๊ทธ ์ด์ ์๋ํ ์ํํธ์จ์ด๋ก ์๋ํ๋ ์ค ์ฝํ ์ธ ์ด์ ํ๊ธฐ ๋ธ๋ก๊ทธ๋ฅผ ์ด์ํ๋ฉด์ ๋ธ๋ก๊ทธ ์ด์ ์ ๋ํ ํ์์ฑ์ ๋๋ผ๊ฒ ๋ฉ๋๋ค. ๊ทธ ์ด์ ๋ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ง๋ง, ์ฃผ๋ก ์ฑ๋ฅ ํฅ์, ๋์์ธ ๋ณ๊ฒฝ,
everydayhub.tistory.com
6. ์ฑ๋ฅ ์ต์ ํ ๋ฐฉ๋ฒ
ํ์ด์ง ํ๋ง
_page_pool = []
def createWindow(self, type):
if _page_pool:
return _page_pool.pop()
return SafeWebEnginePage(self.profile(), self.parent_view)
ํ๋กํ ์ฌ์ฌ์ฉ
_shared_profile = QWebEngineProfile("Shared", self)
def createWindow(self, type):
return SafeWebEnginePage(_shared_profile, self.parent_view)
๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
_shared_profile = QWebEngineProfile("Shared", self)
def createWindow(self, type):
return SafeWebEnginePage(_shared_profile, self.parent_view)
์์ ์ ์ธ ์น๋ทฐ ์ฑ์ ์ํ ํ ๊ฑธ์
์ด ๊ธ์์ ์๊ฐํ createWindow ์ค๋ฅ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋จ์ํ ๊ฒฝ๊ณ ๋ฅผ ๋์ด์, ์น๋ทฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฑ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฒฐ์ ์ง๋ ์ค์ํ ์์๊ฐ ๋ฉ๋๋ค.