Search code examples
pythonpyqtpyqt5bookmarksqwebengineview

Python PyQT - Web Browser | Bookmarks


This is a repost of my previous post which I deleted. In the first post I asked if someone knows a way of creating bookmarks with PyQT5, however, originally, I did not post what issues I am having now, with my way. I have 3 toolbars, in my web browser.

  1. For additional buttons as - exit, minimize, maximize and etc.
  2. For navigation in the web.
  3. Bookmarks all are created with the instance of QToolBar().

Bookmarks toolbar code

self.bookmark_bar = QToolBar('Bookmark')
self.bookmark_bar.setIconSize(QSize(12, 12))
self.bookmark_bar.setMovable(False)
self.addToolBar(self.bookmark_bar)

After the tool bars are created the buttons are added, as there is a lot of code there I will show just the final result as a screenshot and the last few lines of code in init function.

How the Web Browser looks

The last few lines of code:

self.add_new_tab(QUrl('http://www.google.com'), 'Home Page')
self.bookmarks_load()
self.show()
self.setWindowTitle('Tempo')

Everything is fine with the Web Browser itself, as everything is working except the bookmarks. The line of code 'bookmarks_load()' load the bookmarks from a .txt file. As for now in the .txt document the bookmark is youtube.com (does not matter which link is used). The bookmarks functioncs:

Add a website to a bookmark.txt

def Bookmark(self):
    try:
        qurl = QUrl(self.urlbar.text())
        print('Here we are using the QUrl toString method: %s ---> Type: %s' % (qurl.toString(), type(qurl)))
        url = qurl.toString()
        print('Here we are storing the new string to a new variable: %s ---> Type: %s' % (url, type(url)))
        b = open(os.path.join('bookmarks', 'bookmarks.txt'), "wb")
        self.bookmarks_write = pickle.dump(url, b)
        b.close()
    except:
        print("Crash - Bookmarks not stored")

    self.bookmark_btn.setText("★")

Load bookmarks from the document file.

def bookmarks_load(self):
    try:
        bookmarks_open = open(os.path.join('bookmarks', 'bookmarks.txt'), 'rb')
        self.bookmarks_write = pickle.load(bookmarks_open)
        bookmarks_open.close()
        self.create_bookmarks()
    except:
        bookmarks_open = open(os.path.join('bookmarks', 'bookmarks.txt'), 'wb')
        bookmarks = 'http://www.stackoverflow.com'
        self.bookmarks_write = pickle.dump(bookmarks, bookmarks_open)
        bookmarks_open.close()
        self.create_bookmarks()
        print('Crash - Did not load bookmarks')

Create the bookmarks 'button', when pressed open a new tab with that website.

def create_bookmarks(self):
    bookmark_list = []
    try:
        for book in self.bookmarks_write.split():
            print(book)
            bookmark_list.append(book)
            print(bookmark_list)
    except:
        print("Something went wrong with the list")

    try:
        button = QAction(QIcon(os.path.join('images', 'tab_icon.PNG')), 'Open bookmark', self)
        button.triggered.connect(self.add_new_tab(QUrl(bookmark_list[0]), 'New'))
        self.bookmark_bar.addAction(button)
    except:
        print('Button is causing the error')

Now this is the part which I start having issues. If I remove the - triggered.connect line and I do not add any functionality to that 'button' everything launches and works, without any errors. It stores and can load the bookmarks. However, when that line is added, it crashes and the button is not created(The app does not exit as there is an except statement which catches the error - which pyqt does not show what error it is.). This is the add_new_tab() function:

def add_new_tab(self, qurl=None, label='Blank'):

    if qurl is None:
        qurl = QUrl('')

    web_browser = QWebEngineView()
    web_browser.setUrl(qurl)
    web_browser.adjustSize()
    index = self.tabs.addTab(web_browser, label)

    self.tabs.setCurrentIndex(index)

    web_browser.urlChanged.connect(lambda qurl, web_browser=web_browser:
                                   self.update_urlbar(qurl, web_browser))

    web_browser.loadFinished.connect(lambda _, i=index, web_browser=web_browser:
                                     self.tabs.setTabText(i, web_browser.page().title()))

Originally I open tabs by 'double clicking' on the tab bar with this function:

def tab_open_doubleclick(self, index):
    if index == -1:
        self.add_new_tab()

As you can see on the trigger - I do pass the link as QUrl and I do add a test label. The problem I have it somehow does not want to work and I can not find why, because Python PyQT5 does not show an error, it just closes with the return code.

Screenshots as explanation:


Link not added to a bookmarks.txt

Link not added to a bookmarks.txt

Link added to bookmarks.txt

Link added to bookmarks.txt

Pickle does dump the link in .txt

Pickle does dump the link in .txt

The "except" statement is run, while the triggered.connect line is not commented out.

The "except" statement is run, while the triggered.connect line is not commented out.

The app continues to run, but the loaded bookmarks buttons are not there. Empty bookmarks bar


Solution

  • In the following example I show how to add the functionality of the BookMark, for it use QSettings to store the data but for this you must use setOrganizationName(), setOrganizationDomain() and setApplicationName(). Also I added the functionality of obtaining the title of the web page. The BookMarkToolBar class has the bookmarkClicked method that returns the url associated with the BookMark and the title.

    from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
    
    
    class BookMarkToolBar(QtWidgets.QToolBar):
        bookmarkClicked = QtCore.pyqtSignal(QtCore.QUrl, str)
    
        def __init__(self, parent=None):
            super(BookMarkToolBar, self).__init__(parent)
            self.actionTriggered.connect(self.onActionTriggered)
            self.bookmark_list = []
    
        def setBoorkMarks(self, bookmarks):
            for bookmark in bookmarks:
                self.addBookMarkAction(bookmark["title"], bookmark["url"])
    
        def addBookMarkAction(self, title, url):
            bookmark = {"title": title, "url": url}
            fm = QtGui.QFontMetrics(self.font())
            if bookmark not in self.bookmark_list:
                text = fm.elidedText(title, QtCore.Qt.ElideRight, 150)
                action = self.addAction(text)
                action.setData(bookmark)
                self.bookmark_list.append(bookmark)
    
        @QtCore.pyqtSlot(QtWidgets.QAction)
        def onActionTriggered(self, action):
            bookmark = action.data()
            self.bookmarkClicked.emit(bookmark["url"], bookmark["title"])
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            self.defaultUrl = QtCore.QUrl()
    
            self.tabs = QtWidgets.QTabWidget()
            self.tabs.setTabsClosable(True)
            self.setCentralWidget(self.tabs)
    
            self.urlLe = QtWidgets.QLineEdit()
            self.urlLe.returnPressed.connect(self.onReturnPressed)
            self.favoriteButton = QtWidgets.QToolButton()
            self.favoriteButton.setIcon(QtGui.QIcon("images/star.png"))
            self.favoriteButton.clicked.connect(self.addFavoriteClicked)
    
            toolbar = self.addToolBar("")
            toolbar.addWidget(self.urlLe)
            toolbar.addWidget(self.favoriteButton)
    
            self.addToolBarBreak()
            self.bookmarkToolbar = BookMarkToolBar()
            self.bookmarkToolbar.bookmarkClicked.connect(self.add_new_tab)
            self.addToolBar(self.bookmarkToolbar)
            self.readSettings()
    
        def onReturnPressed(self):
            self.tabs.currentWidget().setUrl(QtCore.QUrl.fromUserInput(self.urlLe.text()))
    
        def addFavoriteClicked(self):
            loop = QtCore.QEventLoop()
    
            def callback(resp):
                setattr(self, "title", resp)
                loop.quit()
    
            web_browser = self.tabs.currentWidget()
            web_browser.page().runJavaScript("(function() { return document.title;})();", callback)
            url = web_browser.url()
            loop.exec_()
            self.bookmarkToolbar.addBookMarkAction(getattr(self, "title"), url)
    
        def add_new_tab(self, qurl=QtCore.QUrl(), label='Blank'):
            web_browser = QtWebEngineWidgets.QWebEngineView()
            web_browser.setUrl(qurl)
            web_browser.adjustSize()
            web_browser.urlChanged.connect(self.updateUlrLe)
            index = self.tabs.addTab(web_browser, label)
            self.tabs.setCurrentIndex(index)
            self.urlLe.setText(qurl.toString())
    
        def updateUlrLe(self, url):
            self.urlLe.setText(url.toDisplayString())
    
        def readSettings(self):
            setting = QtCore.QSettings()
            self.defaultUrl = setting.value("defaultUrl", QtCore.QUrl('http://www.google.com'))
            self.add_new_tab(self.defaultUrl, 'Home Page')
            self.bookmarkToolbar.setBoorkMarks(setting.value("bookmarks", []))
    
        def saveSettins(self):
            settings = QtCore.QSettings()
            settings.setValue("defaultUrl", self.defaultUrl)
            settings.setValue("bookmarks", self.bookmarkToolbar.bookmark_list)
    
        def closeEvent(self, event):
            self.saveSettins()
            super(MainWindow, self).closeEvent(event)
    
    
    if __name__ == '__main__':
        import sys
    
        QtCore.QCoreApplication.setOrganizationName("eyllanesc.org")
        QtCore.QCoreApplication.setOrganizationDomain("www.eyllanesc.com")
        QtCore.QCoreApplication.setApplicationName("MyApp")
        app = QtWidgets.QApplication(sys.argv)
        w = MainWindow()
        w.show()
        sys.exit(app.exec_())
    

    enter image description here