0

I have a QDialog containing a QTabWidget, whose tabs vary in size. Following these instructions, which are similar to another stack overflow answer, I have the following code (self.tabs is a dictionary of the tab widgets):

class Panel(NXDialog):

    def __init__(self, panel, parent=None):
        super(Panel, self).__init__(parent)
        self.tabwidget = QtWidgets.QTabWidget()
        self.tabwidget.currentChanged.connect(self.update)
        ...

    @property
    def tab(self):
        return self.tabwidget.currentWidget()

    def update(self):
        if self.tabwidget.count() == 0:
            self.setVisible(False)
        else:
            for tab in [tab for tab in self.tabs if tab is not self.tab]:
                try:
                    self.tabs[tab].setSizePolicy(QtWidgets.QSizePolicy.Ignored, 
                                                 QtWidgets.QSizePolicy.Ignored)
                    self.tabs[tab].update()
                except Exception:
                    pass
            self.tab.setSizePolicy(QtWidgets.QSizePolicy.Preferred,
                                   QtWidgets.QSizePolicy.Preferred)
            self.tab.update()
        self.adjustSize()

When I add a new tab, this works very well. The tab does resize as I want. However, subsequent changes in the tab selection have no effect, even though my debugger confirms that this update function is called.

My application has an embedded shell that shares a namespace with the GUI so I can address all the PyQt widgets. If I call tab.adjustSize() in the shell, where tab points to the selected tab, the tab does resize! So my question is why the adjustSize function is ignored when I make the selection and trigger the currentChanged signal using the GUI, but is not ignored when I call the same slot function a little later from a shell. I've tried adding a sleep time and recursively cycling through the parent widgets calling adjustSize for each of them, but it has no effect. I've also tried adding self.repaint() as well as programmatically changing focus and back again, but nothing works except typing it from the shell.

I'm running PyQt5 v5.12.5 on Python 3.8 but I get the same behavior with PyQt v5.9.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Ray Osborn
  • 430
  • 5
  • 13
  • please provide a [mre] – eyllanesc May 24 '20 at 21:53
  • I really don't think that would be helpful here, since my application is extremely large with many interconnected parts. This is not a bug report. I am hoping that someone in the community can make suggestions of things to try based on their experience with similar issues. – Ray Osborn May 24 '20 at 22:17
  • Here we need an MRE, if your application is very large then it is not an MRE so you will have to make an effort to create a new project focused only on functionality, and then that will be the MRE. Those are the SO rules. Please read [ask] and review the [tour] – eyllanesc May 24 '20 at 22:19
  • I have read thousands of SO questions that have not provided an MRE and yet have received multiple helpful comments. In fact, I have just come across another SO page that I think solves the issue, but also has no MRE. I will post shortly. – Ray Osborn May 24 '20 at 22:26
  • If the answer already exists then don't post the same answer, also remember that the SO rules have changed. – eyllanesc May 24 '20 at 22:28
  • I have posted the answer because it did not show up when I looked before so the context is obviously different enough. Frankly, I thought that stackoverflow was encouraging a slightly more welcoming response to questions than I have received here (see https://stackoverflow.blog/2018/04/26/stack-overflow-isnt-very-welcoming-its-time-for-that-to-change/). – Ray Osborn May 24 '20 at 22:38
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/214585/discussion-between-ray-osborn-and-eyllanesc). – Ray Osborn May 25 '20 at 12:49

1 Answers1

0

Another stackoverflow question has helped me solve the problem. It seems that the previous changes in SizePolicy might still have been waiting in the GUI event loop. Clearing the loop first ensures that the adjustSize works.

This is all that is needed.

        QtWidgets.QApplication.instance().processEvents()        
        self.adjustSize()

I confess I'm surprised this issue hasn't come up for me before, but I hope it's helpful to anyone else with the same issue.

Ray Osborn
  • 430
  • 5
  • 13
  • Although I think this answer is still basically correct, it has triggered another PyQt5 bug, which causes the application to crash on exit if that widget is still open. I believe that it is the same bug described in the answer by @ekhumoro [here](https://stackoverflow.com/questions/59120337/why-does-pyqt-sometimes-crash-on-exit). I think it affects PyQt5 v5.12 and v5.13 but not v5.9. – Ray Osborn May 25 '20 at 13:07
  • In case anyone is allowed to read this in the future, the problem in the comment above was fixed following a suggestion on the PyQt mailing list (https://www.riverbankcomputing.com/pipermail/pyqt/2020-May/042923.html). The trick is to explicitly close all top-level widgets before call the QApplication quit method. Deleting the QApplication instance itself does not appear to be necessary. – Ray Osborn May 25 '20 at 22:55