2012-02-21 20 views
2

私は現在で定義されたQScrollArea持っている:私が使用している、グリッド列の見出しを提供するなど、他のレイアウト/ウィジェット内にネストされた、非常に喜んで座っているQScrollAreaに固定ヘッダを追加するには?

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) 

、期待通りにリサイズし、

をスクロールエリアのすぐ上に配置された別のQGridLayout - これは機能しますが、オンデマンド(垂直)スクロールバーが必要に応じて表示されたり消えたりすると、ヘッダーが正しく整列しなくなるグリッド列。私が知っている美的なものですが、私はちょっと気分が悪いです。)

他のウィジェットは、別の場所でプログラムでself.results_grid_layoutに追加/削除されています。私は作成されたマージン領域を使用して簡単だろうと思ったように私上記の最後の行は最近、setViewportMargins状態のためdocsを追加しました:スクロール領域の周囲に

設定マージンを。これは、「ロックされた」行と列を持つスプレッドシートなどのアプリケーションに役立ちます。余白は空白のままです。 ウィジェットを未使用領域に配置します。

しかし、私は私の人生のために実際にこれを達成するために、いずれかの私のGoogleFuは私に、今日を捨てた、またはほとんど情報/例は実際にこれを達成するためにどのようにそこにありますかうまくいかないことができます。

私の頭の中には、私が行ったように、スクロールエリアにレイアウト(他のウィジェットをいくつでも含む)によって制御されているウィジェットしか割り当てられないということがあります。たとえば、QHeaderviewをgridlayoutの行0に追加すると、それはビューポートの余白の下に表示され、残りのレイアウトとともにスクロールされます。それとも、私は何かを見逃しているだけで、木の木が見えませんか?

私はちょうどPython/Qtを学んでいるので、どんな助け、ポインタや例(できればPythonで、しかし必須ではありません)をいただければ幸いです!


編集:これまでのアドバイスに従った(と思う)、私は物事を試すには、以下の小さなテストプログラムを思い付いた:

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() 

がメソッドにこれらの線に沿って何かですあなたが指していた?すべてが期待どおりに動作します。ユーザーがウィンドウのサイズを変更する前に、いくつかの奇妙な初期の動作を除いて、すべてが整列して正常に機能しています。 私はおそらくもう一度考えすぎているか、少なくとも何かを見落としています...どんな考えですか?

+0

: 'grid_layout.setSizeConstraint'行をコメントアウトは、問題を解決しているようです。 – ekhumoro

+0

ありがとう、ありがとう。残りのマイナーな問題を自分で解決できると確信しています(主にヘッダーの最初の幅)。あなたの助けは大いに感謝されており、私の正しい道を導いた元の答えを受け入れてくれました。乾杯。 – DazGreen

答えて

1

少し考え過ぎているかもしれません。

スクロールエリアのジオメトリと現在のマージンを使用して、マージンに配置するウィジェットのジオメトリを計算するだけです。

これらのウィジェットのジオメトリは、スクロールエリアのresizeEventでも更新する必要があります。

QTableViewのソースコードを見ると、この方法を使用してヘッダービュー(または非常に似ているもの)を管理することができます。

は、あなたのテストケースでマイナーなサイズ変更の問題に対処するには、[編集]、私はQRectためのドキュメントでCoordinatesセクションを読み取るために、あなたを助言する(具体的には、第三段落以降)。

私はこのようなテストケースを書き換えることにより、より正確なサイズ変更を取得することができた:

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_()) 
+0

ああ、面白い、ありがとう。さて、ジオメトリ、マージンを取得する方法と、必要なサイズと配置を得るために必要な計算を、これらの更新とともに行うことができます。だから私は、レイアウトのaddWidgetメソッドを使ってヘッダウィジェットを組み込む必要はなく、単に作成し、ジオメトリを設定し、setParentを使ってレイアウトの子にして、それがグリッドと一緒に破棄されるようにすることができます不要になりました?私は、QTableViewのソース[1282](http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/itemviews/qtableview.cpp#line1282)を見ました。 C++ – DazGreen

+0

@DazGreen。ヘッダーはレイアウトの一部であってはなりません。ですから 'grid_widget'の子にしてください。私が参照していた 'QTableView'ソースは、' 'updateGeometries''(http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/itemviews/qtableview.cpp#line2033)メソッドにあります - うまくいけば分かりやすい_lot_を見つけてください。 – ekhumoro

+0

優れています。私ができるとすぐに、私の開発マシンに戻って、私はこれを渦巻にしてポストバックします(またupvoteして、それが私のためにパン、私はその時までの担当者を持っている場合はこの答えを受け入れる)。御時間ありがとうございます。 – DazGreen

0

私は同様の問題を抱えていたし、少し違った、それを解決しました。 1つのQScrollAreaを使用する代わりに、下側のスクロール領域を2つ使用して先頭のものに移動します。以下のコードは、

  1. です。QVBoxLayoutに2つのQScrollAreaウィジェットを作成します。
  2. 上部QScrollAreaのスクロールバーの表示を無効にし、固定された高さに割り当てます。
  3. 低いQScrollAreaの水平スクロールバーのvalueChanged信号を使用すると、下部のQScrollAreaからの水平スクロールバーの値を、そのウィンドウの上部に固定された上部ヘッダーになる「トップ」に「転送」することができます。

    クラスのメインウィンドウ(QMainWindow): DEF のinit(自己、親=なし): スーパー(メインウィンドウ、自己)。 のinit(親)テストプログラムに

    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.

関連する問題