z3ntu / QtWaitingSpinner

A waiting spinner ported to Python 3 and PyQt6
MIT License
85 stars 21 forks source link

Alternative example doesn't seem to work #2

Open romanrdgz opened 6 years ago

romanrdgz commented 6 years ago

I have a QDialog with QTabWidget. Using the alternative example, I was somehow expecting the spinner to appear as an overlay, over the tabs, centered in the parent widget (the QDialog). Nevertheless, it doesn't show up.

This is a short example of downloading a file and expecting the spinner to show up:

from PyQt5.QtWidgets import QApplication, QDialog, QTabWidget, QWidget, QGroupBox, QPushButton, QVBoxLayout
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
import requests
import urllib
from waitingspinnerwidget import QtWaitingSpinner

class DownloadDataDialog(QDialog):
    def __init__(self, parent=None):
        super(DownloadDataDialog, self).__init__(parent)

        self.spinner = QtWaitingSpinner(self, True, True, Qt.ApplicationModal)

        tabWidget = QTabWidget(self)
        tabWidget.addTab(MyTab(tabWidget), "MyTab")

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(tabWidget)
        self.setLayout(mainLayout)

        self.setWindowTitle("Download option chain data from web")

class MyTab(QWidget):
    def __init__(self, parent=None):
        super(MyTab, self).__init__(parent)

        dataGroup = QGroupBox('Data')

        getButton = QPushButton('Download')
        getButton.clicked.connect(self.download_data)

        dataLayout = QVBoxLayout()
        dataLayout.addWidget(getButton)
        dataGroup.setLayout(dataLayout)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(dataGroup)
        mainLayout.addStretch(1)
        self.setLayout(mainLayout)

    def download_data(self):
        self.parent().parent().parent().spinner.start()
        url = 'http://www.meff.es/docs/Ficheros/Descarga/dRV/RV180912.zip'
        filepath = None
        try:
            filepath = self.download_data_file(url)
        except Exception as e:
            print(e)

        self.parent().parent().parent().spinner.stop()
        if filepath:
            #TODO doing stuff here
            self.parent().parent().parent().close()
        else:
            pass #TODO show error dialog

    def download_data_file(self, download_url):           
        # Build request URL and download the file
        destination = 'test.zip'
        urllib.request.urlretrieve(download_url, destination)
        return destination

if __name__ == '__main__':

    import sys

    app = QApplication(sys.argv)

    tabdialog = DownloadDataDialog()
    tabdialog.show()
    sys.exit(app.exec_())

Am I doing something wrong?

z3ntu commented 6 years ago

After looking at the original C++ QtWaitingSpinner code, I also don't think that modal thing worked there.

You can patch it locally for now, so it kind of works.

diff --git a/waitingspinnerwidget.py b/waitingspinnerwidget.py
index 12f273b..8573ef5 100644
--- a/waitingspinnerwidget.py
+++ b/waitingspinnerwidget.py
@@ -34,7 +34,7 @@ from PyQt5.QtWidgets import *

 class QtWaitingSpinner(QWidget):
     def __init__(self, parent, centerOnParent=True, disableParentWhenSpinning=False, modality=Qt.NonModal):
-        super().__init__(parent)
+        super().__init__(parent, Qt.Dialog | Qt.FramelessWindowHint)

         self._centerOnParent = centerOnParent
         self._disableParentWhenSpinning = disableParentWhenSpinning
@@ -187,8 +187,11 @@ class QtWaitingSpinner(QWidget):

     def updatePosition(self):
         if self.parentWidget() and self._centerOnParent:
-            self.move(self.parentWidget().width() / 2 - self.width() / 2,
-                      self.parentWidget().height() / 2 - self.height() / 2)
+#            dialogCenter = self.mapToGlobal(self.rect().center());
+#            parentWindowCenter = self.parentWidget().window().mapToGlobal(self.parentWidget().window().rect().center())
+#            self.move(parentWindowCenter - dialogCenter)
+            parentRect = QRect(self.parentWidget().mapToGlobal(QPoint(0, 0)), self.parentWidget().size())
+            self.move(QStyle.alignedRect(Qt.LeftToRight, Qt.AlignCenter, self.size(), parentRect).topLeft())

     def lineCountDistanceFromPrimary(self, current, primary, totalNrOfLines):
         distance = primary - current

But also in your example, somehow the urllib request is blocking the QTimer in the waiting spinner so it doesn't show at all. If you remove that call (and the calls to stop the spinner and close the window) and apply the patch above you should see the spinner spinning.

romanrdgz commented 6 years ago

It works now, but you are right: it doesn't work with urllib, don't know why.

It seems someone fixed it in Stackoverflow: https://stackoverflow.com/questions/52313073/making-an-invisible-layer-in-pyqt-which-covers-the-whole-diaglo/52316134#52316134