Gauthier Buttez
Gauthier Buttez

Reputation: 1193

How to open a http.server from a Qt5 gui without blocking the gui?

I made a UI with Python 3.7 and Qt5.

There is a button which launch a local http.server and open a page to show some report data.

The problem is when I click on button, it run my script, launch the server and open the page correctly but my ui is blocked. It is like waiting the server finish its job before ui works again.

I’ve read multithreading is not good with ui Tq. Is there any trick to open the http.server independently from my ui?

Code if the method run by the button:

def OpenReport():
    class ReportHTTPHandler (http.server.SimpleHTTPRequestHandler):
        def run_cgi(self, reportclass):
            # Setup environment variables -
            _, _, query = self.path.partition ('?')

            os.environ['QUERY_STRING'] = query

            # Cookies
            co = filter (None, self.headers.get_all ('cookie', []))
            cookie_str = ', '.join (co)
            if cookie_str:
                os.environ['HTTP_COOKIE'] = cookie_str

            cgitb.enable ()

            f = io.StringIO ()
            with redirect_stdout (f):
                reportclass.runCGI (self)

            output = f.getvalue ()
            self.send_response (HTTPStatus.OK, '')
            self.flush_headers ()

            self.wfile.write (''.join (output).encode ())
            self.wfile.flush ()
            return

        def send_head(self):
            # Split the query string for parsing later
            path, _, query = self.path.partition ('?')
            # Check if URL is a report
            # This is not the neatest way
            if path == '/cgi/index.py':
                return ReportHTTPHandler.run_cgi (self, ReportIndex)
            elif path == '/cgi/facebook.py':
                return ReportHTTPHandler.run_cgi (self, ReportFacebook)
            elif path == '/cgi/google-map.py':
                return ReportHTTPHandler.run_cgi (self, ReportGoogleMap)
            elif path == '/cgi/instagram.py':
                return ReportHTTPHandler.run_cgi (self, ReportInstagram)
            elif path == '/cgi/linkedin.py':
                return ReportHTTPHandler.run_cgi (self, ReportLinkedIn)
            elif path == '/cgi/sms.py':
                return ReportHTTPHandler.run_cgi (self, ReportSMS)
            elif path == '/cgi/telegram.py':
                return ReportHTTPHandler.run_cgi (self, ReportTelegram)
            elif path == '/cgi/twitter.py':
                return ReportHTTPHandler.run_cgi (self, ReportTwitter)
            else:
                # Assume this is an asset
                return http.server.SimpleHTTPRequestHandler.send_head (self)


    port = 50000
    address = ("", port)
    server = http.server.HTTPServer

    handler = ReportHTTPHandler

    httpd = server (address, handler)
    print (f"Report tool server started on port {port}")
    webbrowser.open (f'http://localhost:{port}/cgi/index.py', new=2)

    try:
        httpd.serve_forever ()
    except KeyboardInterrupt:
        print ("\nKeyboard interrupt received, exiting.")
        sys.exit (0)

Code which load the ui and run the server:

# === Load the UI =========================================
gui = QtWidgets.QApplication([])
ui = uic.loadUi('ui/MyUI.ui')
ui.button_Report.clicked.connect(OpenReport)
ui.show()
gui.exec()

Upvotes: 0

Views: 400

Answers (1)

WenJuan
WenJuan

Reputation: 684

You can launch your server in thread when button click and signal the status back to your UI

def buttonClick(self):
   t = threading.Thread(target=self.startServer)
   t.start()

def startServer(self):
   *Launch Server
   self.progress_signal.emit("Complete")

Upvotes: 1

Related Questions