2015-08-31 35 views
8

Wdrażam aplikację python za pomocą PyQt5 i napotkałem pewne problemy podczas korzystania z QScrollArea. Jest to układ z mojego wniosku:Qt.ScrollBarAsNeeded nie pokazuje paska przewijania, gdy jest on rzeczywiście potrzebny

enter image description here

To składa się z 2 QScrollArea (lewy i prawy panel) oraz QMdiArea (centrum widget) umieszczoną na QHBoxLayout. Po rozwinięciu widżetów na lewym panelu, klikając elementy sterujące, a wysokość QWidget obiektu QScrollArea jest większa niż wysokość samego paska przewijania (zgodnie z oczekiwaniami), ale nakłada się na zawartość . Aby rozwiązać ten problem mam przepisany na resizeEvent dodając niezbędną przestrzeń do przewijania (do tego punktu wszystko działa.

enter image description here

Teraz, kiedy ręcznie zmienić rozmiar okna głównego, w lewym okienku dostaje więcej przestrzeni i pasek przewijania powinny zniknąć (ale to nie robi) i nakłada widgety z panelu:

enter image description here

próbowałem też ręcznie przełączyć widoczność paska przewijania (po otrzymaniu resizeEvent): kiedy to zrobić , Mogę skutecznie ukryć t przesuwa pasek, ale nie mogę go ponownie wyświetlić (nie ma znaczenia, jeśli zadzwonię na setVisible(True) na pasku przewijania). Powoduje to, że miejsca na pasku przewijania dodawane, ale przewijania brakuje, a zawartość okienka nie jest przewijane:

enter image description here

Oto realizacja widget szyby:

class Pane(QScrollArea): 

    MinWidth = 186 

    def __init__(self, alignment=0, parent=None): 
     super().__init__(parent) 
     self.mainWidget = QWidget(self) 
     self.mainLayout = QVBoxLayout(self.mainWidget) 
     self.mainLayout.setAlignment(alignment) 
     self.mainLayout.setContentsMargins(0, 0, 0, 0) 
     self.mainLayout.setSpacing(0) 
     self.setContentsMargins(0, 0, 0, 0) 
     self.setFrameStyle(QFrame.NoFrame) 
     self.setFixedWidth(Pane.MinWidth) 
     self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 
     self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) 
     self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Ignored) 
     self.setWidgetResizable(True) 
     self.setWidget(self.mainWidget) 

    def resizeEvent(self, resizeEvent): 
     if self.viewport().height() < self.widget().height(): 
      self.setFixedWidth(Pane.MinWidth + 18) 
      # THIS DOESN'T WORK 
      #self.verticalScrollBar().show() 
     else: 
      self.setFixedWidth(Pane.MinWidth) 
      #self.verticalScrollBar().hide() 

    def addWidget(self, widget): 
     self.mainLayout.addWidget(widget) 

    def removeWidget(self, widget): 
     self.mainLayout.removeWidget(widget) 

    def update(self, *__args): 
     for item in itemsInLayout(self.mainLayout): 
      item.widget().update() 
     super().update(*__args) 

Co chcę osiągnąć jest dość proste (ale praktycznie nie wydaje się tak proste): Chciałbym dynamicznie pokazać pionowy pasek przewijania w moich widgetach po lewej/prawej stronie tylko wtedy, gdy jest to potrzebne, i dodać niezbędne miejsce na pasek przewijania, aby nie nakłada się na widżety w QScrollArea.

Zanim ktoś pyta, ja już próbowałem zrobić coś takiego:

def resizeEvent(self, resizeEvent): 
    if self.viewport().height() < self.widget().height(): 
     self.setFixedWidth(Pane.MinWidth + 18) 
     scrollbar = self.verticalScrollbar() 
     scrollbar.setVisible(True) 
     self.setVerticalScrollBar(scrollbar) ## APP CRASH 
    else: 
     self.setFixedWidth(Pane.MinWidth) 
     #self.verticalScrollBar().hide() 

co skutkuje w mojej aplikacji do awarii. Mam nadzieję, że ktoś już napotkał ten problem i jest w stanie mi pomóc.

EDYCJA: Używam PyQt5.5 skompilowany przeciwko Qt5.5 pod OS X Yosemite 10.10.4 przy użyciu clang.

+0

spróbować najpierw ustawić 'setWidgetResizable' true dla scrollArea –

+0

to już ustawione To prawda, więc domyślam się, że problem jest gdzieś indziej –

Odpowiedz

3

Wszystko wydaje się działać zgodnie z oczekiwaniami, bez potrzeby obejścia problemu. Jednak mocno podejrzewam, że istnieją dodatkowe ograniczenia w twoim prawdziwym kodzie, których nie ujawniłeś w swoim pytaniu.

UPDATE

Poniżej znajduje się prosty przykład, który zmienia rozmiar scrollareas gdy paski przewijania są wyświetlane/ukryte:

import sys 
from PyQt5 import QtCore, QtGui, QtWidgets 

class Window(QtWidgets.QMainWindow): 
    def __init__(self): 
     super(Window, self).__init__() 
     widget = QtWidgets.QWidget(self) 
     layout = QtWidgets.QHBoxLayout(widget) 
     self.mdi = QtWidgets.QMdiArea(self) 
     self.leftScroll = Pane(
      QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft, self) 
     self.rightScroll = Pane(
      QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft, self) 
     layout.addWidget(self.leftScroll) 
     layout.addWidget(self.mdi) 
     layout.addWidget(self.rightScroll) 
     self.setCentralWidget(widget) 
     for scroll in self.leftScroll, self.rightScroll: 
      for index in range(4): 
       widget = QtWidgets.QTextEdit() 
       widget.setText('one two three four five') 
       scroll.addWidget(widget) 

class Pane(QtWidgets.QScrollArea): 
    MinWidth = 186 

    def __init__(self, alignment=0, parent=None): 
     super().__init__(parent) 
     self.mainWidget = QtWidgets.QWidget(self) 
     self.mainLayout = QtWidgets.QVBoxLayout(self.mainWidget) 
     self.mainLayout.setAlignment(alignment) 
     self.mainLayout.setContentsMargins(0, 0, 0, 0) 
     self.mainLayout.setSpacing(0) 
     self.setContentsMargins(0, 0, 0, 0) 
     self.setFrameStyle(QtWidgets.QFrame.NoFrame) 
     self.setFixedWidth(Pane.MinWidth) 
     self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) 
     self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) 
     self.setSizePolicy(QtWidgets.QSizePolicy.Maximum, 
          QtWidgets.QSizePolicy.Ignored) 
     self.setWidgetResizable(True) 
     self.setWidget(self.mainWidget) 
     self.verticalScrollBar().installEventFilter(self) 

    def addWidget(self, widget): 
     self.mainLayout.addWidget(widget) 

    def removeWidget(self, widget): 
     self.mainLayout.removeWidget(widget) 

    def eventFilter(self, source, event): 
     if isinstance(source, QtWidgets.QScrollBar): 
      if event.type() == QtCore.QEvent.Show: 
       self.setFixedWidth(Pane.MinWidth + source.width()) 
      elif event.type() == QtCore.QEvent.Hide: 
       self.setFixedWidth(Pane.MinWidth) 
     return super(Pane, self).eventFilter(source, event) 

if __name__ == '__main__': 

    app = QtWidgets.QApplication(sys.argv) 
    window = Window() 
    window.setGeometry(500, 300, 800, 300) 
    window.show() 
    sys.exit(app.exec_()) 
+0

dzięki, spróbuję jak tylko będę mógł –

+0

Próbowałem twojego kodu, a problem nadal występuje: http://i.imgur.com/O2o0iil.png . Na jakiej platformie próbowałeś kodu? może to problem tylko dla OSX. –

+0

@ DanielePantaleone. Tak, podejrzewałem, że są w to zaangażowane inne czynniki. Jestem na Linuksie i nie mogę testować na OSX. Prawdopodobnie powinieneś edytować swoje pytanie, aby jasno określić, które wersje OSX i Qt używasz. Pomogłoby to również w przypadku dodania najprostszego możliwego przykładu, który odtwarza problem dla ciebie na OSX: może to być pojedynczy "QScrollArea" zawierający jeden widżet. – ekhumoro