Domanda

Attualmente ho un QScrollarea definito da:

self.results_grid_scrollarea = QScrollArea()
self.results_grid_widget = QWidget()
self.results_grid_layout = QGridLayout()
self.results_grid_layout.setSizeConstraint(QLayout.SetMinAndMaxSize)
self.results_grid_widget.setLayout(self.results_grid_layout)
self.results_grid_scrollarea.setWidgetResizable(True)
self.results_grid_scrollarea.setWidget(self.results_grid_widget)
self.results_grid_scrollarea.setViewportMargins(0,20,0,0)

che si trova abbastanza felicemente nidificato all'interno di altri layout/widget, ridimensiona come previsto, ecc.

Per fornire titoli per le colonne della griglia, sto usando un altro qgridlayout posizionato direttamente sopra l'area di scorrimento - questo funziona ... ma sembra un po 'strano, anche quando è stato disegnato in modo appropriato, specialmente quando la barra di scorrimento su richiesta (verticale) appare o scompare Se necessario e le intestazioni non si allineano più correttamente con le colonne della griglia. È una cosa estetica che so ... ma sono un po 'esigente;)

Altri widget vengono aggiunti/rimossi al self.results_grid_layout programmaticamente altrove. L'ultima riga sopra ho appena aggiunto di recente perché pensavo che sarebbe stato facile usare l'area del margine creata, il Documenti Per SetViewPortMargins State:

Imposta i margini attorno all'area di scorrimento. Ciò è utile per applicazioni come fogli di calcolo con righe e colonne "bloccate". Lo spazio marginale è lasciato vuoto; Metti i widget nell'area inutilizzata.

Ma non posso per la vita di me capire come raggiungere questo obiettivo, e il mio Googlefu mi ha abbandonato oggi, o ci sono poche informazioni/esempi là fuori su come raggiungere questo obiettivo.

La mia testa mi sta dicendo che posso assegnare solo un widget, controllato da un layout (contenente un numero qualsiasi di altri widget) allo scrollata - come ho fatto. Se aggiungo dire un Qheaderview, ad esempio alla riga 0 di GridLayout, apparirà solo sotto il margine del Viewport e scorri con il resto del layout? O mi manca qualcosa e non riesco a vedere il legno per gli alberi?

Sto solo imparando Python/Qt, quindi qualsiasi aiuto, puntatori e/o esempi (preferibilmente con Python ma non essenziale) sarebbe apprezzato!


EDIT: avendo seguito il consiglio dato finora (penso), ho trovato il seguente piccolo programma di test per provare le cose:

import sys
from PySide.QtCore import *
from PySide.QtGui import *

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setMinimumSize(640, 480)

        self.container_widget = QWidget()
        self.container_layout = QVBoxLayout()
        self.container_widget.setLayout(self.container_layout)
        self.setCentralWidget(self.container_widget)

        self.info_label = QLabel(
            "Here you can see the problem.... I hope!\n"
            "Once the window is resized everything behaves itself.")
        self.info_label.setWordWrap(True)

        self.headings_widget = QWidget()
        self.headings_layout = QGridLayout()
        self.headings_widget.setLayout(self.headings_layout)
        self.headings_layout.setContentsMargins(1,1,0,0)

        self.heading_label1 = QLabel("Column 1")
        self.heading_label1.setContentsMargins(16,0,0,0)
        self.heading_label2 = QLabel("Col 2")
        self.heading_label2.setAlignment(Qt.AlignCenter)
        self.heading_label2.setMaximumWidth(65)
        self.heading_label3 = QLabel("Column 3")
        self.heading_label3.setContentsMargins(8,0,0,0)
        self.headings_layout.addWidget(self.heading_label1,0,0)
        self.headings_layout.addWidget(self.heading_label2,0,1)
        self.headings_layout.addWidget(self.heading_label3,0,2)
        self.headings_widget.setStyleSheet(
            "background: green; border-bottom: 1px solid black;" )

        self.grid_scrollarea = QScrollArea()
        self.grid_widget = QWidget()
        self.grid_layout = QGridLayout()
        self.grid_layout.setSizeConstraint(QLayout.SetMinAndMaxSize)
        self.grid_widget.setLayout(self.grid_layout)
        self.grid_scrollarea.setWidgetResizable(True)
        self.grid_scrollarea.setWidget(self.grid_widget)
        self.grid_scrollarea.setViewportMargins(0,30,0,0)
        self.headings_widget.setParent(self.grid_scrollarea)
        ### Add some linedits to the scrollarea just to test
        rows_to_add = 10
        ## Setting the above to a value greater than will fit in the initial
        ## window will cause the lineedits added below to display correctly,
        ## however - using the 10 above, the lineedits do not expand to fill
        ## the scrollarea's width until you resize the window horizontally.
        ## What's the best way to fix this odd initial behaviour?
        for i in range(rows_to_add):
            col1 = QLineEdit()
            col2 = QLineEdit()
            col2.setMaximumWidth(65)
            col3 = QLineEdit()
            row = self.grid_layout.rowCount()
            self.grid_layout.addWidget(col1,row,0)
            self.grid_layout.addWidget(col2,row,1)
            self.grid_layout.addWidget(col3,row,2)
        ### Define Results group to hold the above sections
        self.test_group = QGroupBox("Results")
        self.test_layout = QVBoxLayout()
        self.test_group.setLayout(self.test_layout)
        self.test_layout.addWidget(self.info_label)
        self.test_layout.addWidget(self.grid_scrollarea)
        ### Add everything to the main layout
        self.container_layout.addWidget(self.test_group)


    def resizeEvent(self, event):
        scrollarea_vpsize = self.grid_scrollarea.viewport().size()
        scrollarea_visible_size = self.grid_scrollarea.rect()
        desired_width = scrollarea_vpsize.width()
        desired_height = scrollarea_visible_size.height()
        desired_height =  desired_height - scrollarea_vpsize.height()
        new_geom = QRect(0,0,desired_width+1,desired_height-1)
        self.headings_widget.setGeometry(new_geom)


def main():
    app = QApplication(sys.argv)
    form = MainWindow()
    form.show()
    app.exec_()

if __name__ == '__main__':
   main()

Qualcosa in questo senso è il metodo a cui stavi indicando? Tutto funziona come previsto come è esattamente quello che stavo dopo, tranne uno strano comportamento iniziale prima che la finestra venga ridimensionata dall'utente, una volta ridimensionato tutto si allinea e va bene. Probabilmente sto pensando di nuovo o almeno a trascurare qualcosa ... qualche pensiero?

È stato utile?

Soluzione

Potresti essere leggermente pensando alle cose.

Tutto quello che devi fare è usare la geometria del punto di vista dello scrollata e i margini attuali per calcolare la geometria di eventuali widget che si desidera posizionare ai margini.

La geometria di questi widget dovrebbe anche essere aggiornata nel resizeEvent dello scrollata.

Se guardi il codice sorgente per QTableView, Penso che scoprirai che usi questo metodo per gestire le sue viste di intestazione (o qualcosa di molto simile).

MODIFICARE

Per affrontare i problemi di ridimensionamento minori nel caso del test, ti consiglierei di leggere il Coordinate sezione nei documenti per QRect (In particolare, il terzo paragrafo in poi).

Sono stato in grado di ottenere un ridimensionamento più accurato riscrivendo il tuo caso di test in questo modo:

import sys
from PySide.QtCore import *
from PySide.QtGui import *

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setMinimumSize(640, 480)
        self.container_widget = QWidget()
        self.container_layout = QVBoxLayout()
        self.container_widget.setLayout(self.container_layout)
        self.setCentralWidget(self.container_widget)
        self.grid_scrollarea = ScrollArea(self)
        self.test_group = QGroupBox("Results")
        self.test_layout = QVBoxLayout()
        self.test_group.setLayout(self.test_layout)
        self.test_layout.addWidget(self.grid_scrollarea)
        self.container_layout.addWidget(self.test_group)

class ScrollArea(QScrollArea):
    def __init__(self, parent=None):
        QScrollArea.__init__(self, parent)
        self.grid_widget = QWidget()
        self.grid_layout = QGridLayout()
        self.grid_widget.setLayout(self.grid_layout)
        self.setWidgetResizable(True)
        self.setWidget(self.grid_widget)
        # save the margin values
        self.margins = QMargins(0, 30, 0, 0)
        self.setViewportMargins(self.margins)
        self.headings_widget = QWidget(self)
        self.headings_layout = QGridLayout()
        self.headings_widget.setLayout(self.headings_layout)
        self.headings_layout.setContentsMargins(1,1,0,0)
        self.heading_label1 = QLabel("Column 1")
        self.heading_label1.setContentsMargins(16,0,0,0)
        self.heading_label2 = QLabel("Col 2")
        self.heading_label2.setAlignment(Qt.AlignCenter)
        self.heading_label2.setMaximumWidth(65)
        self.heading_label3 = QLabel("Column 3")
        self.heading_label3.setContentsMargins(8,0,0,0)
        self.headings_layout.addWidget(self.heading_label1,0,0)
        self.headings_layout.addWidget(self.heading_label2,0,1)
        self.headings_layout.addWidget(self.heading_label3,0,2)
        self.headings_widget.setStyleSheet(
            "background: green; border-bottom: 1px solid black;" )
        rows_to_add = 10
        for i in range(rows_to_add):
            col1 = QLineEdit()
            col2 = QLineEdit()
            col2.setMaximumWidth(65)
            col3 = QLineEdit()
            row = self.grid_layout.rowCount()
            self.grid_layout.addWidget(col1,row,0)
            self.grid_layout.addWidget(col2,row,1)
            self.grid_layout.addWidget(col3,row,2)

    def resizeEvent(self, event):
        rect = self.viewport().geometry()
        self.headings_widget.setGeometry(
            rect.x(), rect.y() - self.margins.top(),
            rect.width() - 1, self.margins.top())
        QScrollArea.resizeEvent(self, event)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    form = MainWindow()
    form.show()
    sys.exit(app.exec_())

Altri suggerimenti

Ho avuto un problema simile e l'ho risolto in modo leggermente diverso. Invece di usarne uno QScrollarea Uso due e inoltro un movimento dell'area di scorrimento inferiore a quella superiore. Quello che fa il codice seguente è

  1. Crea due widget QSCrollarea in un QVBoxLayout.
  2. Disabilita la visibilità delle barre di scorrimento della QScrollaa superiore e le assegna un'altezza fissa.
  3. Usando il valutato Il segnale della barra di scorrimento orizzontale della QScrollaa inferiore è possibile "inoltrare" il valore della barra di scorrimento orizzontale dal QScrollaa inferiore alla parte superiore, risultando un'intestazione fissa nella parte superiore della finestra.

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        widget = QWidget()
        self.setCentralWidget(widget)

        vLayout = QVBoxLayout()
        widget.setLayout(vLayout)

        # TOP
        scrollAreaTop = QScrollArea()
        scrollAreaTop.setWidgetResizable(True)
        scrollAreaTop.setFixedHeight(30)
        scrollAreaTop.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scrollAreaTop.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scrollAreaTop.setWidget(QLabel(" ".join([str(i) for i in range(100)])))

        # BOTTOM
        scrollAreaBottom = QScrollArea()
        scrollAreaBottom.setWidgetResizable(True)
        scrollAreaBottom.setWidget(QLabel("\n".join([" ".join([str(i) for i in range(100)]) for _ in range(10)])))
        scrollAreaBottom.horizontalScrollBar().valueChanged.connect(lambda value: scrollAreaTop.horizontalScrollBar().setValue(value))

        vLayout.addWidget(scrollAreaTop)
        vLayout.addWidget(scrollAreaBottom)

Window resulting from above code.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top