2017-01-28 46 views
1

我在gridlaayout中的所有元素上都保留了一些大小。如何保持PyQt Grid元素的大小不變並保持所有小部件的間距?

Ocasionally內小部件只是完全改變大小我更新的情節數據(在寬度和高度)之後,特別是最大化/最小化或改變窗口尺寸後:

試驗#1 enter image description here 運行# 2 enter image description here

我希望實現的是要保持大小均勻分佈,無論窗口的尺寸:

所需的輸出: enter image description here

這是我編寫的填充網格以及如何更新CSS以使邊框更改顏色的摘要。我注意到,如果我不改變CSS,那麼這個問題就不明顯了。

class ResultsViewer(QtGui.QWidget): 
    plots = {} #the currently displayed plot widgets 
    curves = {} #the currently displayed data that store the points 

    def __init__(self): 
     super(ResultsViewer, self).__init__() 
     self.win = QtGui.QMainWindow() 
     self.win.setCentralWidget(self) 
     self.win.resize(800, 250) 
     self.win.setWindowTitle("Cavity Results Viewer") 
     self.grid = QtGui.QGridLayout(self) 
     self.win.setWindowFlags(self.win.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) 

    def reset_indicators(self): 
     for plot in self.plots.keys(): 
      self.plots[plot].setStyleSheet(""" 
           border-top: 5px solid rgba(0,0,0,0); 
           border-radius: 12px; 
           """) 

    def set_indicator_border_color(self, cavnum, result): 
     color = "lime" if result['decision'] else "red" 
     self.plots[cavnum].setStyleSheet(""" 
         border-top: 5px solid %s; 
         border-radius: 12px; 
         """ % color) 

    def create_indicators(self, params): 
     for c, cavnum in enumerate(params.keys()): 
      r = (4 % (c + 1))/4 #every fourth column jump to next row 

      box = QtGui.QHBoxLayout() 

      plt = pg.PlotWidget() 

      plt.setStyleSheet(""" 
         border-top: 5px solid yellow; 
         border-radius: 12px; 
        """) 
      curve_blue = plt.plotItem.plot(pen=None, symbol='o', symbolPen=None, symbolSize=8, symbolBrush=(100, 100, 255, 80)) #points for showing history data 
      curve_green = plt.plotItem.plot(pen=None, symbol='o', symbolPen=None, symbolSize=8,symbolBrush=(100, 255, 100, 80)) 
      curve_blue_last = plt.plotItem.plot(pen=None, symbol='x', symbolPen=None, symbolSize=18, symbolBrush=(50, 50, 255, 255)) #points for showing the newest data 
      curve_green_last = plt.plotItem.plot(pen=None, symbol='x', symbolPen=None, symbolSize=18,symbolBrush=(50, 255, 50, 255)) 

      plt.plotItem.setLabel('left', "Amplitude", units='A') 
      plt.plotItem.setLabel('bottom', "Frequency", units='Hz') 
      self.plots[cavnum] = plt 
      self.curves[cavnum] = {"blue": curve_blue, 
            "blue_last": curve_blue_last, 
            "green": curve_green, 
            "green_last": curve_green_last} 
      box.addWidget(plt) 
      self.grid.addLayout(box, r, c % 4) 

    def update(self, cavnum, results): 
     #update the plots and render all points 
     ... 
     ... 
     self.set_indicator_border_color(cavnum, result) 

[更新]

這是一個全功能的例子:

import sys, time 
import random 
import numpy as np 
import pyqtgraph as pg 
from PyQt4 import QtCore, QtGui 

class ResultsViewer(QtGui.QWidget): 
    plots = {} #the currently displayed plot widgets 
    curves = {} #the currently displayed data that store the points 

    def __init__(self): 
     super(ResultsViewer, self).__init__() 
     self.win = QtGui.QMainWindow() 
     self.win.setCentralWidget(self) 
     self.win.resize(800, 250) 
     self.win.setWindowTitle("Cavity Results Viewer") 
     self.grid = QtGui.QGridLayout(self) 
     self.win.setWindowFlags(self.win.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) 

     self.win.show() 

    def reset_indicators(self): 
     #return #Uncomment this to skip modifying the CSS (resizing problem seems to go away!!!) 
     for plot in self.plots.keys(): 
      self.plots[plot].setStyleSheet(""" 
           border-top: 5px solid rgba(0,0,0,0); 
           border-radius: 12px; 
           """) 

    def set_indicator_border_color(self, cavnum, result): 
     #return #Uncomment this to skip modifying the CSS (resizing problem seems to go away!!!) 
     color = "lime" if result['decision'] else "red" 
     self.plots[cavnum].setStyleSheet(""" 
         border-top: 5px solid %s; 
         border-radius: 12px; 
         """ % color) 

    def create_indicators(self, params): 
     for c, cavnum in enumerate(params.keys()): 
      r = (4 % (c + 1))/4 #every fourth column jump to next row 

      box = QtGui.QHBoxLayout() 

      plt = pg.PlotWidget() 

      plt.setStyleSheet(""" 
         border-top: 5px solid yellow; 
         border-radius: 12px; 
        """) 
      curve_blue = plt.plotItem.plot(pen=None, symbol='o', symbolPen=None, symbolSize=8, symbolBrush=(100, 100, 255, 80)) #points for showing history data 
      curve_green = plt.plotItem.plot(pen=None, symbol='o', symbolPen=None, symbolSize=8,symbolBrush=(100, 255, 100, 80)) 


      plt.plotItem.setLabel('left', "Amplitude", units='A') 
      plt.plotItem.setLabel('bottom', "Frequency", units='Hz') 
      self.plots[cavnum] = plt 
      self.curves[cavnum] = {"blue": curve_blue, 
            "green": curve_green} 
      box.addWidget(plt) 
      self.grid.addLayout(box, r, c % 4) 

    def update(self, cavnum, results): 
     #update the plots and render all points 
     max_history = 1000 #max points per plot to store 

     result = results[cavnum] 
     if result.has_key('peaks'): 
      peaks = result['peaks'] 

      if peaks.has_key('amps'): 
       amps = np.round(peaks['amps'], 2) 
       freqs = np.round(peaks['freqs'], 2) 

       x_blue, y_blue = self.curves[cavnum]['blue'].getData() 
       x_blue = np.append(freqs, x_blue)[:max_history] 
       y_blue = np.append(amps, y_blue)[:max_history] 

       x_blue = x_blue[x_blue != np.array(None)] #remove any none from the initial getData 
       y_blue = y_blue[y_blue != np.array(None)] #remove any none from the initial getData 
       self.curves[cavnum]['blue'].setData(x_blue, y_blue) 

     self.set_indicator_border_color(cavnum, result) 

class MyThread(QtCore.QThread): 
    update = QtCore.pyqtSignal(int, object) 

    def __init__(self, resutls, parent=None): 
     super(MyThread, self).__init__(parent) 
     self.results = resutls #number of plots 

    def run(self): 
     while True: 
      for cavnum in range(len(self.results.keys())): 
       time.sleep(1) 
       peaks = {'amps': np.random.rand(3,1), 'freqs': np.random.rand(3,1)} 
       self.results[cavnum]['decision'] = bool(random.getrandbits(1)) 
       self.results[cavnum]['peaks'] = peaks 
       self.update.emit(cavnum, self.results) 


# create the dialog for zoom to point 
class MainApp(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(MainApp, self).__init__(parent) 
     # Set up the user interface from Designer. 

     n = 8 
     results = {} 
     for x in range(n): 
      results[x] = {} 

     self.thread = MyThread(results) 
     self.thread.update.connect(self.update) 

     self.viewer = ResultsViewer() 
     self.viewer.create_indicators(results) 

     self.thread.start() 

    def update(self, cavnum, data): 
     self.viewer.update(cavnum, data) 

if __name__ == "__main__": 
    app = QtGui.QApplication([]) 
    widget = MainApp() 
    widget.move(300, 300) 
    widget.show() 
sys.exit(app.exec_()) 
+2

你介意提供[MCVE]嗎?否則這裏很難說什麼。 – ImportanceOfBeingErnest

+1

新添加的示例不會爲我運行(在各個地方有'結果'有多個問題,一旦修復'.setData'會引發錯誤)。我修改了代碼,使其實際運行並再現問題,找到它[**](http://pastebin.com/afFLmsSP)**。我沒有發現問題,但至少在這個代碼中,每個人都可以更輕鬆地看看它。 – ImportanceOfBeingErnest

+0

你說得對我的例子有錯誤。我很抱歉,我認爲我做了一個編輯,忘了做一個複製粘貼測試。非常感謝您閱讀代碼並使其更具可讀性!我也修復了我對我的例子所做的破解編輯。 – Logic1

回答

1

考慮一個更簡單的例子讓我找到解決方案。 似乎將styleSheet設置爲PlotWidget可讓小部件自行調整大小,從而與QGridLayout協商更多或更少的空間。風格不會改變Widget的大小並不重要,即使設置完全不相關的內容,如字體甚至無效的樣式都會重現問題。使用正常QWidget而不是PlotWidget不會產生此問題。

在任何情況下,解決方案因此需要告知QGridLayout不要更改其列和行的空間。 這可以使用
QGridLayout.setColumnStretch (self, int column, int stretch)
QGridLayout.setRowStretch (self, int row, int stretch)

其中stretch需要爲所有行/列相同,且大於零來完成。請參閱下面的最小示例。相應地調整實際代碼應該是相當直接的。

import sys, time 
import numpy as np 
import pyqtgraph as pg 
from PyQt4 import QtCore, QtGui 

class MainApp(QtGui.QMainWindow): 

    def __init__(self): 
     super(MainApp, self).__init__() 

     self.win = QtGui.QWidget() 
     self.setCentralWidget(self.win) 
     self.resize(800, 250) 
     self.grid = QtGui.QGridLayout() 
     self.win.setLayout(self.grid) 
     self.colors = ["yellow", "green", "red", "blue"] 
     self.n = 8 
     self.create_boxes() 
     self.thread = MyThread() 
     self.thread.update.connect(self.setBoxColor) 
     self.thread.start() 
     self.show() 


    def create_boxes(self): 
     self.boxes = [] 
     for i in range(self.n): 
      r = (4 % (i + 1))/4 
      box = pg.PlotWidget() 
      #box = QtGui.QWidget() # problem does not appear when using QWidget 
      self.boxes.append(box) 
      self.setBoxColor(i,0) 
      ######### 
      # The following two lines solve the problem!!! 
      # comment them out to see old unwanted behaviour 
      self.grid.setColumnStretch(i % 4, 1) 
      self.grid.setRowStretch(r, 1) 
      ######### 
      self.grid.addWidget(box, r, i % 4) 



    def setBoxColor(self, boxnumber, color): 
     stylesheet = """ 
         border-top: 5px solid %s; 
         border-radius: 12px; 
         """ % self.colors[color] 
     self.boxes[boxnumber].setStyleSheet(stylesheet) 


class MyThread(QtCore.QThread): 
    update = QtCore.pyqtSignal(int, int) 

    def __init__(self, parent=None): 
     super(MyThread, self).__init__(parent) 

    def run(self): 
     time.sleep(1) 
     while True: 
      boxnumber = np.random.randint(0,8) 
      color = np.random.randint(0,4) 
      self.update.emit(boxnumber, color) 
      time.sleep(0.34) 



if __name__ == "__main__": 
    app = QtGui.QApplication([]) 
    widget = MainApp() 
    widget.move(300, 300) 
    widget.show() 
    sys.exit(app.exec_()) 
+0

這絕對能解決我的問題。我將繼續關注列和行拉伸方法。謝謝! – Logic1

相關問題