title: How to add a fixed header to a QScrollArea?
body: <p>I currently have a QScrollArea defined by:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>which sits quite happily nested within other layouts/widgets, resizes as expected, etc. </p>
  
  <p>To provide headings for the grid columns, I'm using another QGridLayout positioned directly above the scroll area - this works... but looks a little odd, even when styled appropriately, especially when the on-demand (vertical) scrollbar appears or disappears as needed and the headers no longer line up correctly with the grid columns.  It's an aesthetic thing I know... but I'm kinda picky ;)</p>
  
  <p>Other widgets are added/removed to the <code>self.results_grid_layout</code> programatically elsewhere.  The last line above I've just recently added as I thought it would be easy to use the created margin area, the <a href="http://developer.qt.nokia.com/doc/qt-4.7/qabstractscrollarea.html#setViewportMargins" rel="nofollow">docs</a> for setViewportMargins state:</p>
  
  <blockquote>
    <blockquote>
      <blockquote>
        <p>Sets margins around the scrolling area. This is useful for applications such as spreadsheets with "locked" rows and columns. The marginal space is is left blank; <strong>put widgets in the unused area.</strong></p>
      </blockquote>
    </blockquote>
  </blockquote>
  
  <p>But I cannot for the life of me work out how to actually achieve this, and either my GoogleFu has deserted me today, or there's little information/examples out there on how to actually achieve this.</p>
  
  <p>My head is telling me I can assign just one widget, controlled by a layout (containing any number of other widgets) to the scrollarea - as I have done.  If I add say a QHeaderview for example to row 0 of the gridlayout, it will just appear below the viewport's margin and scroll with the rest of the layout?  Or am I missing something and just can't see the wood for the trees?</p>
  
  <p>I'm just learning Python/Qt, so any help, pointers and/or examples (preferably with Python but not essential) would be appreciated!</p>
  
  <hr>
  
  <p>Edit: Having followed the advice given so far (I think), I came up with the following little test program to try things out:</p>
  
  <pre><code>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()
  </code></pre>
  
  <p>Is something along these lines the method to which you were pointing?  Everything works as expected as is exactly what I was after, except for some odd initial behaviour before the window is resized by the user, once it is resized everything lines up and is fine.
  I'm probably over-thinking again or at least overlooking something... any thoughts?</p>