2017-01-28 27 views
1

У меня возникли проблемы с сохранением размера даже на всех элементах моей gridLayout.Как сохранить элементы сетки PyQt от изменения размера и поддерживать равномерное расстояние от всех виджетов?

Ocasionally внутренние виджеты просто полностью изменить размер после того, как я обновить данные графика (на обеих ширине и высоте), и особенно после того, как максимизация/уменьшения или изменения размера окна:

Run # 1 enter image description here Run # 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) 

[UPDATE]

И это полностью функциональный пример:

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

Учитывая еще более упрощенный пример заставил меня найти решение. Кажется, что установка стиля таблицы в PlotWidget позволяет виджету изменять размер и, таким образом, вести переговоры более или менее с помощью QGridLayout. Не имеет значения, что стиль не изменит размер виджета, даже если установить что-то совершенно несвязанное, как шрифт или даже недопустимые стили, воспроизводит проблему. Использование обычной 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