0

I'm trying to use a QPushButton to call a function that opens a new instance of QWebView. Works but as soon as the window opens it closes again. I've read this - PyQt window closes immediately after opening but I don't understand how to reference the window to keep it open.

import sys
from PyQt4 import QtCore, QtGui, QtWebKit
from PyQt4.QtWebKit import QWebSettings
from PyQt4.QtNetwork import QNetworkAccessManager
from PyQt4.QtNetwork import *



UA_STRING = """Test Test Test""" 
vidurl = ("empty")

def web1():

    class YWebPage(QtWebKit.QWebPage):
        def __init__(self):
            super(QtWebKit.QWebPage, self).__init__()

        def userAgentForUrl(self, url):
            return UA_STRING


    class Browser(QtGui.QMainWindow): # "Browser" window


        def __init__(self):
            QtGui.QMainWindow.__init__(self)
            self.resize(800,600) # Viewport size
            self.centralwidget = QtGui.QWidget(self)
            self.html = QtWebKit.QWebView()


        def browse(self):
            self.webView = QtWebKit.QWebView()
            self.yPage = YWebPage()
            self.webView.setPage(self.yPage)
            self.webView.load(QtCore.QUrl(vidurl)) # Video URL
            self.webView.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled,True) # Enables flash player
            self.webView.show()

    x = Browser()
    # QNetworkProxy.setApplicationProxy(QNetworkProxy(QNetworkProxy.HttpProxy, "proxy.example.com", 8080)) # Proxy setting
    x.browse()



def main(): # Dialog window

    app = QtGui.QApplication(sys.argv)

    w = QtGui.QWidget()

    w.resize(200, 450)
    w.setFixedSize(200, 350)
    w.move(300, 300)
    w.setWindowTitle('U-bot 0.1')

    # Setup GUI

    # Start Button
    w.__button = QtGui.QPushButton(w)
    w.__button.clicked.connect(lambda: web1())

    # Text area
    w.__qle = QtGui.QLineEdit(w)
    w.__qle.setText ("http://")
    vidurl = w.__qle.text # Get video url from user

    # Images
    pixmap1 = QtGui.QPixmap("ubot.png")
    lbl1 = QtGui.QLabel(w)
    lbl1.resize(200, 150)
    lbl1.setPixmap(pixmap1)
    lbl1.setScaledContents(True)

    w.__button.setText('Start')
    layout = QtGui.QVBoxLayout()
    layout.addStretch(1)

    layout.addWidget(w.__qle)
    layout.addWidget(w.__button)


    w.setLayout(layout)
    w.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
    app.exec_()
Community
  • 1
  • 1
metalayer
  • 69
  • 2
  • 9

2 Answers2

6

Create a MainWindow class that keeps a list of open Browsers, and every time when you open a browser, just add it to the list. And when a browser window closes, it will remove itself from the list, see closeEvent.

import sys
from PyQt4 import QtCore, QtGui, QtWebKit
from PyQt4.QtWebKit import QWebSettings
from PyQt4.QtNetwork import QNetworkAccessManager
from PyQt4.QtNetwork import *


UA_STRING = """Test Test Test""" 
vidurl = ("empty")

class YWebPage(QtWebKit.QWebPage):
    def __init__(self):
        super(YWebPage, self).__init__()

    def userAgentForUrl(self, url):
        return UA_STRING


class Browser(QtGui.QMainWindow): # "Browser" window
    def __init__(self, main, url):
        QtGui.QMainWindow.__init__(self)
        self.main = main
        self.resize(800,600) # Viewport size
        self.webView = QtWebKit.QWebView()
        self.setCentralWidget(self.webView)
        self.yPage = YWebPage()
        self.webView.setPage(self.yPage)
        self.webView.load(QtCore.QUrl(url)) # Video URL
        self.webView.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True) # Enables flash player

    def closeEvent(self, event):
        self.main.browsers.remove(self)
        super(Browser, self).closeEvent(event)


class MainWindow(QtGui.QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.browsers = []

        self.resize(200, 450)
        self.setFixedSize(200, 350)
        self.move(300, 300)
        self.setWindowTitle('U-bot 0.1')

        # Setup GUI

        # Start Button
        self.__button = QtGui.QPushButton('Start')
        self.__button.clicked.connect(self.open)

        # Text area
        self.__qle = QtGui.QLineEdit()
        self.__qle.setText("http://")

        # Images
        pixmap1 = QtGui.QPixmap("ubot.png")
        lbl1 = QtGui.QLabel()
        lbl1.resize(200, 150)
        lbl1.setPixmap(pixmap1)
        lbl1.setScaledContents(True)

        layout = QtGui.QVBoxLayout()
        layout.addStretch(1)

        layout.addWidget(self.__qle)
        layout.addWidget(self.__button)

        self.setLayout(layout)

    def open(self):
        b = Browser(self, self.__qle.text())
        b.show()
        self.browsers.append(b)


def main():
    app = QtGui.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
Viktor Kerkez
  • 45,070
  • 12
  • 104
  • 85
  • 2
    Perfect answer to this question. The reason why the window closes was that it lost it has no reference anymore after execution. The function was called, popped up a window and after that it was cleared from the memory since the function was done. When you link it to an existing class by using `self` you can avoid this. This answer is even better since it appends the new window to a list object. I think it's a great solution to keep your code clean. – Ecno92 Aug 05 '13 at 15:27
  • Thanks for responding. – metalayer Aug 05 '13 at 16:19
5

To keep a reference to a QObject, you can either keep the variable in scope, or add it as the child of another QObject which variable already stays in scope.

And for QWidget, the parent should also be a QWidget, so, in your case, you'd want to make w as the parent of all your QMainWindows.

def web1(parent):
    ...
    class Browser(QtGui.QMainWindow): # "Browser" window
        def __init__(self, parent):
            QtGui.QMainWindow.__init__(self, parent)
            ...

def main():
    ...
    w.__button.clicked.connect(lambda: web1(w))

This also avoid maintaining manually a list of opened windows, since the object hierarchy can do that for you.

PS: The child windows are shown as toplevel windows and not inside the w window, because QMainWindow (and QDialog) has the Qt::Window flag set by default.

alexisdm
  • 29,448
  • 6
  • 64
  • 99
  • Thanks, went with this. – metalayer Aug 05 '13 at 16:15
  • "To keep a reference to a QObject, you can either keep the variable in scope" was all i needed to know. That little tidbit of knowledge clicked for me - I added a line of code which keptthe object in scope to my script, and my QWidget window remained alive rather than instantly disappearing as it had been. – 10mjg Jan 23 '16 at 04:50