when a JavaScript program requests to open a document in a new window, QWebEnginePage::createWindow() would be called to create a new window, while I want to (1) open the new window using QDesktopServices.openUrl(url) instead, and (2) keep the view in my QWebEngineView unchanged. My solution cannot satisfy (2), so any simpler solutions ?
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWebEngineCore import *
import sys,os
class WebEnginePage(QWebEnginePage):
def __init__(self, parent, mdicts=[]):
super().__init__(parent)
self.backwardUrl=''
def acceptNavigationRequest(self, url, navigationType, isMainFrame): # Navigation requests can be delegated to the Qt application instead of having the HTML handler engine process them by overloading this function. This is necessary when an HTML document is used as part of the user interface, and not to display external data, for example, when displaying a list of results.# The QWebEngineUrlRequestInterceptor class offers further options for intercepting and manipulating requests.
# print('acceptNavigationRequest-----------------', navigationType, isMainFrame)
if self.backwardUrl and isMainFrame:
print('blocked------------',self.backwardUrl)
self.setUrl(self.backwardUrl)
QDesktopServices.openUrl(self.backwardUrl)
self.backwardUrl=''
return False
return True
def createWindow(self, windowType):
print('createWindow')
self.backwardUrl=self.url()
return self
class WebEngineView(QWebEngineView):
def __init__(self, parent=None):
super().__init__(parent)
# self.mousePressEvent=lambda event:print('mousePressEvent',event.pos())
# self.mouseMoveEvent=lambda event:print('mouseMoveEvent',event.pos())
self.webPage = WebEnginePage(self)#self.page() # QWebEnginePage()
self.setPage(self.webPage)
# self.setUrl(QUrl('https://dict.eudic.net/liju/en/good#TingLiju'))
self.webPage.setUrl(QUrl('https://dict.eudic.net/liju/en/good#TingLiju'))
if __name__ == "__main__":
app = QApplication(sys.argv)
webEngineView = WebEngineView()
webEngineView.show()
sys.exit(app.exec_())
A possible solution is to create a page that only serves to obtain the url, and when you get it, delete it and launch the url with QDesktopServices::openUrl():
class FakePage(QWebEnginePage):
def __init__(self, parent=None):
super().__init__(parent)
self.urlChanged.connect(self.handle_url_changed)
#pyqtSlot(QUrl)
def handle_url_changed(self, url):
QDesktopServices.openUrl(url)
self.deleteLater()
class WebEnginePage(QWebEnginePage):
def createWindow(self, windowType):
return FakePage(self)
class WebEngineView(QWebEngineView):
def __init__(self, parent=None):
super().__init__(parent)
self.webPage = WebEnginePage(self)
self.setPage(self.webPage)
self.webPage.setUrl(QUrl("https://dict.eudic.net/liju/en/good#TingLiju"))
Related
I wrote a plugin in PyQGIS, which contains several Ui's (using QT Designer). When I run the code in the QGIS Python console, it works wonderfully. Now I would like to make it available internally for the company as a classic QGIS plugin (start in menu bar). It always worked well with previous plugins, but there was always only one Ui.
At its core there are three important files. 1. __ init __.py, 2. geowerkzeug.py, which is responsible for starting from the menu, and 3. functionality.py, which contains all my functions.
##__init__.py
from Plugin.geowerkzeug import GeoWerkzeug
def classFactory(iface):
plugin = GeoWerkzeug(iface)
return plugin
Now the geowerkzeug.py:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from plugin.functionality import *
from qgis.utils import iface
import os
class GeoWerkzeug:
def __init__ (self, iface):
self.iface = iface
def initGui (self):
self.startButton = QAction("Plugin starten", self.iface.mainWindow())
self.iface.addPluginToMenu('Plugin', self.startButton)
self.startButton.triggered.connect(self.maskeAufrufen)
def unload (self):
self.iface.removePluginMenu('Plugin', self.startButton)
def maskeAufrufen (self):
self.gui = MainWindow(self)
dock_widget = QDockWidget("Plugin", self.iface.mainWindow())
dock_widget.setWidget(self.gui)
self.iface.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock_widget)
dock_widget.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
self.gui.show()
Up to here it works. MainWindow is the first class on functionality.py. The window will appear. But if I click on a button to switch to the next Ui (class), the Ui does not change. I have a total of 17 Ui's in my plugin. Here I only show two classes as an example.
Now the functionality.py:
from PyQt5.uic import loadUi
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from PyQt5 import *
from qgis.core import *
from qgis.utils import iface
from qgis.gui import *
import processing
from PyQt5 import uic
import os
pluginPath = os.path.dirname(__file__)
uiPath = os.path.join(pluginPath, 'mainwindow.ui')
uiPath_second_window = os.path.join(pluginPath, 'window2.ui')
WIDGET, BASE = uic.loadUiType(uiPath)
widget = QDockWidget()
class MainWindow(BASE, WIDGET):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.gui = loadUi(uiPath, self)
self.window_second.clicked.connect(self.next_window)
def next_window(self):
window_the_second=Second_window()
widget.setWidget(window_the_second)
class Second_window(BASE, WIDGET):
def __init__(self):
super(Second_window, self).__init__()
self.gui = loadUi(uiPath_second_window , self)
My biggest problem with understanding is how to correctly link my code from functionality.py (which runs in the console) with the other two files. The next problem is that I don't even get an error message that I could build on. The plugin is in the menu bar and it can be started, but after that I can't get any further. I hope my explanations are understandable.
The main issue which causes the second window not to appear, is that you never show the QDockWidget. With widget.setWidget(window_the_second) you set the content, but it doesn't make the window appear.
In your method that shows the first window, add the dockwidget with self.iface.addDockWidget(QtCore.Qt.RightDockWidgetArea, widget)
then set your first window as content of that dockwidget (widget.setWidget(self.gui)).
In general, you got some things a bit mixed up, so I'll try to clarify two points.
The contents of a window are set by subclassing the results of uic.loadUiType. In order to have a second window display your second ui, you can't sublass the same BASE and WIDGET. Call uic.loadUiType for each of your UI-Files instead.
You are missing a call to setupUi() to initialize the UI. Then you can also get rid of any loadUi.
Implementing my advices then results in the following:
WIDGET, BASE = uic.loadUiType('1.ui')
WIDGET2, BASE2 = uic.loadUiType('2.ui')
widget = QDockWidget()
class GeoWerkzeug:
def __init__ (self, iface):
self.iface = iface
def initGui (self):
self.startButton = QAction("Plugin starten", self.iface.mainWindow())
self.iface.addPluginToMenu('Plugin', self.startButton)
self.startButton.triggered.connect(self.maskeAufrufen)
def unload (self):
self.iface.removePluginMenu('Plugin', self.startButton)
def maskeAufrufen (self):
# add DockWidget to GUI
self.iface.addDockWidget(QtCore.Qt.RightDockWidgetArea, widget)
widget.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
# set first window as content of the DockWidget
self.gui = MainWindow(self)
widget.setWidget(self.gui)
class MainWindow(BASE, WIDGET):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.setupUi(self)
self.window_second.clicked.connect(self.next_window)
def next_window(self):
# set second window as content of the DockWidget
window_the_second=Second_window()
widget.setWidget(window_the_second)
class Second_window(BASE2, WIDGET2):
def __init__(self):
super(Second_window, self).__init__()
self.setupUi(self)
I have made a web browser using pyqt5 and PyQtWebEngine.It works fine but when I click on a hyperlink with target="_blank" then it does not work but how will I fix it. You can view its source code by clicking on this link https://github.com/SaptakBhoumik/WebPlus
. Please review my code and tell me what to do
As noted in the docs:
_blank: usually a new tab, but users can configure browsers to open a new window instead.
That is, the objective is not to reload the page but to create a new tab, and then to obtain that request you must override the createWindow method of QWebEngineView (or QWebEnginePage):
from functools import cached_property
import sys
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
class WebView(QtWebEngineWidgets.QWebEngineView):
def createWindow(self, type_):
if not isinstance(self.window(), Browser):
return
if type_ == QtWebEngineWidgets.QWebEnginePage.WebBrowserTab:
return self.window().tab_widget.create_tab()
class TabWidget(QtWidgets.QTabWidget):
def create_tab(self):
view = WebView()
index = self.addTab(view, "(Untitled)")
self.setTabIcon(index, view.icon())
view.titleChanged.connect(
lambda title, view=view: self.update_title(view, title)
)
view.iconChanged.connect(lambda icon, view=view: self.update_icon(view, icon))
self.setCurrentWidget(view)
return view
def update_title(self, view, title):
index = self.indexOf(view)
self.setTabText(index, title)
def update_icon(self, view, icon):
index = self.indexOf(view)
self.setTabIcon(index, icon)
class Browser(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setCentralWidget(self.tab_widget)
view = self.tab_widget.create_tab()
view.load(
QtCore.QUrl(
"https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_a_target"
)
)
#cached_property
def tab_widget(self):
return TabWidget()
def main():
app = QtWidgets.QApplication(sys.argv)
w = Browser()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Note: I recommend that you review the official example: WebEngine Widgets Simple Browser Example, in addition to its implementation in PySide2 which is easily translatable to PyQt5 where this feature and many more are implemented.
I have got two main-windows which will run all the time and open other windows. Every window has to communicate with each other. All windows are created with qt designer and as I read in another question I should not modify these files, so I tried to make a new class (communicator) to handle all the jobs.
What is the best way to structure a project like this. So how can i communicate best between these windows now, e.g. if I press a button in 'self.mainWindows_images' I want to do something in 'self.mainWindows_classifier'
from classifier import Form as Form_classifier
from cnn_avg import Form as Form_cnn_avg
from images import Form as Form_images
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class Communicator():
def __init__(self, parent=None):
self.mainWindow_images = Form_images()
self.mainWindow_images.show()
self.mainWindow_classifier = Form_classifier()
self.mainWindow_classifier.show()
def main():
app = QApplication(sys.argv)
app.setStyle('cleanlooks')
comm = Communicator()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
One of the window files, generated by Qt Designer, looks like with the additional -w flag:
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(1145, 654)
...
class Form(QtGui.QWidget, Ui_Form):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QWidget.__init__(self, parent, f)
self.setupUi(self)
I want to do something like this and add the setImage-method to the mainWindow_classifier, becaus as I mentioned I should not modify the generated qt python file:
self.mainWindow_classifier.pushButton.clicked.connect(self.setImage)
def setImage(self):
# change QLabel in self.mainWindow_images
so I've made several GUIs using the PyQt designer and I aim for each of them to link with eachother and for them to be able to open eachother. I have gotten the start up page to open up the home page, however when I click the respective buttons on the home page to open the other pages, it crashes my program. Any help would in fixing this would be greatly appreciated.
My code is below:
import sys
from PyQt5 import QtGui, QtCore, QtWidgets
from StartupPage import Ui_StartupWindow
from HomePage import Ui_HomeWindow
from FoodPage import Ui_FoodWindow
from ExercisePage import Ui_ExerciseWindow
from ProfilePage import Ui_ProfileWindow
class Startup(QtWidgets.QMainWindow, Ui_StartupWindow):
def __init__(self, parent=None):
super(Startup, self).__init__(parent)
self.setupUi(self)
self.NewEntryButton.clicked.connect(self.NewButtonHandle)
self.ContinueButton.clicked.connect(self.ContinueButtonHandle)
self.HomeP=Home()
def NewButtonHandle(self):
self.HomeP.show()
def ContinueButtonHandle(self):
self.HomeP.show()
class Home(QtWidgets.QMainWindow, Ui_HomeWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.FoodP=Food()
self.ExerciseP=Exercise()
self.ProfileP=Profile()
self.exerciseButton.clicked.connect(self.ExerciseButtonHandle)
self.foodButton.clicked.connect(self.FoodButtonHandle)
self.profileButton.clicked.connect(self.ProfileButtonHandle)
def ExerciseButtonHandle():
self.ExerciseP.show()
def FoodButtonHandle():
self.FoodP.show()
def ProfileButtonHandle():
self.ProfileP.show()
class Food(QtWidgets.QMainWindow, Ui_FoodWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
class Exercise(QtWidgets.QMainWindow, Ui_ExerciseWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
class Profile(QtWidgets.QMainWindow, Ui_ProfileWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Startup()
window.show()
sys.exit(app.exec_())
try to move import sys to:
if __name__ == '__main__':
import sys """<--------------------------here"""
app = QtWidgets.QApplication(sys.argv)
window = Startup()
window.show()
sys.exit(app.exec_())
try to check that other you import modules such as this.
It could be useful to know what error message is displayed when the program crashes.
Having said that, I was fiddling with something similar recently and the below seems to work fine. Note it is mostly the same as what you were doing.
Also, I had wanted to prevent interaction with the main (home) window when any of it's child windows (window1, window2, window3) were open, to force the user to focus on one task at a time rather than opening multiple windows - hence the setEnabled() calls. The
self.Window1.setEnabled(True)
line is required in home.toWindow1() because the Window1 is a member of home, and as such gets disabled along with all other members of home as a result of the first setEnabled call.
Also, while I did put my
import sys
in the main method as suggested by Volodymyr, that's just for the sake of neatness. As references to sys will resolve just as well (scoping rules, LEGB) if the import is the first line of code or the first line in the main method, I don't see how having it in either location could cause any issues (unless it was imported at the start of the file and then later the variable sys was assigned a different value).
I also don't see that altering the import, as suggested by Bahnzo, from
from HomePage import Ui_HomeWindow
to
import HomePage
and then later referring to Ui_HomeWindow as HomePage.Ui_HomeWindow would make any difference, for the same reason - the only case it would is if Ui_homePage had some value explicitly assigned to it after the import occurred and before it was used in the class definition - and you can see that doesn't happen in the OP's code.
#!/bin/python3
from PyQt5.QtWidgets import QApplication, QMainWindow
from startwindow import Ui_startWindow
from homewindow import Ui_homeWindow
from window1 import Ui_Window1
from window2 import Ui_Window2
from window3 import Ui_Window3
class start(QMainWindow, Ui_startWindow):
def __init__(self):
super(start, self).__init__(None)
self.setupUi(self)
self.homeButton.clicked.connect(self.toHome)
self.home = home()
def toHome(self):
self.home.show()
self.hide()
class home(QMainWindow, Ui_homeWindow):
def __init__(self):
super(home, self).__init__(None)
self.setupUi(self)
self.window1Button.clicked.connect(self.toWindow1)
self.window2Button.clicked.connect(self.toWindow2)
self.window3Button.clicked.connect(self.toWindow3)
self.Window1 = window1(self)
self.Window2 = window2(self)
self.Window3 = window3(self)
def toWindow1(self):
self.Window1.show()
self.setEnabled(False)
self.Window1.setEnabled(True)
def toWindow2(self):
self.Window2.show()
self.setEnabled(False)
self.Window2.setEnabled(True)
def toWindow3(self):
self.Window3.show()
self.setEnabled(False)
self.Window3.setEnabled(True)
def reEnable(self):
self.setEnabled(True)
class window1(QMainWindow, Ui_Window1):
def __init__(self, home):
super(window1, self).__init__(home)
self.home = home
self.setupUi(self)
self.homeButton.clicked.connect(self.toHome)
def toHome(self):
self.home.setEnabled(True)
self.hide()
class window2(QMainWindow, Ui_Window2):
def __init__(self, home):
super(window2, self).__init__(home)
self.home = home
self.setupUi(self)
self.homeButton.clicked.connect(self.toHome)
def toHome(self):
self.home.setEnabled(True)
self.hide()
class window3(QMainWindow, Ui_Window3):
def __init__(self, home):
super(window3, self).__init__(home)
self.home = home
self.setupUi(self)
self.homeButton.clicked.connect(self.toHome)
def toHome(self):
self.home.setEnabled(True)
self.hide()
Try this:
import Homepage #import the whole thing
then:
class Home(QtWidgets.QMainWindow, Homepage.Ui_HomeWindow):
#import the UI there
Assume I have two UI files from Qt Designer:mainform.ui stores mdiArea and figureslist.ui stores listView.
Now I'd like to create a mdi application, that can open numbers of figureList windows.
import sys
from PyQt4 import QtGui
#from PyQt4.QtGui import *
from PyQt4 import QtCore, QtGui, uic
class HelloWorldApplication(QtGui.QApplication):
def __init__(self, args):
QtGui.QApplication.__init__(self, args)
self.maindialog = MainUI(None)
class MainUI(QtGui.QMainWindow):
def __init__(self, parent):
QtGui.QMainWindow.__init__(self, parent)
self.ui = uic.loadUi("mainform.ui")
self.ui.show()
# create child and show it
child = self.createFiguresListView()
# problem here (*)
child.show()
def createFiguresListView(self):
child = FiguresListView()
self.ui.mdi.addSubWindow(child)
return child
class FiguresListView(QtGui.QWidget):
def __init__(self):
super(FiguresListView, self).__init__()
self.ui = uic.loadUi("figureslist.ui")
app = HelloWorldApplication(sys.argv)
sys.exit(app.exec_())
But unfortunately my child window shows up collapsed without layout described in figureslist.ui, but acts like mdi child, but if I replace code marked with (*) to child.ui.show() it shows actual layout, but doesn't act like mdi child.
What's wrong?
You forgot to set the parent for the ui (also, if you didn't specified minimum size in Designer, you need to do it here):
class FiguresListView(QtGui.QWidget):
def __init__(self):
super(FiguresListView, self).__init__()
self.ui = uic.loadUi("figureslist.ui", self)
#self.setMinimumSize(400, 200)