2017-09-15 11 views
3

J'essaie de créer un interface graphique simple qui affiche la disposition (de la mémoire) de certains composants d'un périphérique, mais j'ai du mal à faire respecter la politique que je veux à la zone affichée.
Permettez-moi d'abord montrer ce que je suis à ce jour (mon code est devenu assez grand, mais je changé/rétrécies le code jusqu'à la minimale requise pour quiconque de pouvoir l'exécuter):PyQt: Comment configurer les barres de défilement et la politique de taille de la zone d'affichage dans QGraphicsView

#!/usr/local/bin/python3 
from PyQt5.QtCore import * 
from PyQt5.QtGui import * 
from PyQt5.QtWidgets import * 
import sys 

class Register(QGraphicsRectItem): 

    RegisterSize = 125 

    NameColor = QColor(Qt.blue) 
    ValueColor = QColor(0, 154, 205) 

    def __init__(self, name, value, pos, parent = None): 
     super(Register, self).__init__(parent) 
     self.setPos(pos) 

     self.width = Register.RegisterSize 
     self.height = 0 

     self.set_register_name(name) 
     self.set_register_value(value) 

     self.setRect(0, 0, self.width, self.height) 

    def set_register_name(self, name): 
     self.text_item = QGraphicsTextItem(name, self) 
     self.text_item.setDefaultTextColor(Register.NameColor) 
     self.height += self.text_item.boundingRect().height() 

    def set_register_value(self, value): 
     self.value_item = QGraphicsTextItem(str(value), self) 
     self.value_item.setDefaultTextColor(Register.ValueColor) 
     self.value_item.setPos(self.text_item.boundingRect().bottomLeft()) 
     self.height += self.value_item.boundingRect().height() 

class Title(QGraphicsTextItem): 

    TitleFont = 'Times New Roman' 
    TitleFontSize = 18 
    TitleColor = QColor(Qt.red) 

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

     self.setFont(QFont(Title.TitleFont, Title.TitleFontSize)) 
     self.setDefaultTextColor(Title.TitleColor) 

class Component(QGraphicsItem): 

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

     self.width = Register.RegisterSize * 4 
     self.height = 0 

     self.add_title() 
     self.add_registers() 

     self.rect = QRectF(0, 0, self.width, self.height) 

    def add_title(self): 
     self.title = Title('Component Layout', self) 
     self.title.setPos((self.width - self.title.boundingRect().width())/2, 0) 
     self.height += self.title.boundingRect().height() 

    def add_registers(self): 
     y_coor = self.height 
     x_coor = 0 
     for i in range(64): 
      register = Register('register {0:d}'.format(i), i, QPointF(x_coor, y_coor), self) 
      x_coor = ((i + 1) % 4) * Register.RegisterSize 
      if (i + 1) % 4 == 0: 
       y_coor += register.rect().height() 

     self.height = y_coor 

    def boundingRect(self): 
     return self.rect.adjusted(-1, -1, 1, 1) 

    def paint(self, painter, option, widget): 
     pen = QPen(Qt.blue) 
     painter.setPen(pen) 
     painter.drawRect(self.rect) 

class Device(QGraphicsItem): 

    LeftMargin = 50 
    RightMargin = 50 

    TopMargin = 20 
    BottomMargin = 20 

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

     self.width = Device.LeftMargin + Device.RightMargin 
     self.height = Device.TopMargin + Device.BottomMargin 

     component = Component(self) 
     component.setPos(QPointF(Device.LeftMargin, Device.TopMargin)) 
     self.width += component.boundingRect().width() 
     self.height += component.boundingRect().height() 

     self.rect = QRectF(0, 0, self.width, self.height) 

    def paint(self, painter, option, widget): 
     pass 

    def boundingRect(self): 
     return self.rect.adjusted(-1, -1, 1, 1) 

class MainForm(QDialog): 

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

     self.scene = QGraphicsScene(parent) 
     self.view = QGraphicsView(self) 


     self.view.setScene(self.scene) 
     self.scene.addItem(Device()) 
     self.resize(700, 900) 


def run_app(): 
    app = QApplication(sys.argv) 
    form = MainForm() 
    form.show() 
    app.exec_() 

if __name__ == '__main__': 
    run_app() 

Ce code, lors de son lancement, affiche les éléments suivants:

enter image description here

Je ne me dérange pas la barre de défilement verticale, car je compte ajouter d'autres composants à l'appareil, et ils ne seront pas tous s'adapter, ce qui me dérange est le barre de défilement horizontale.
Pourquoi apparaît-il sans que je demande explicitement?
Ce n'est pas comme s'il n'y avait pas de place dans la fenêtre pour que le QGraphicsView affiche le contenu.

De plus, je remarque que les horizontales (et verticales) des barres de défilement ne semblent pas, lorsque seul le composant est ajouté au QGraphicsView:

self.scene.addItem(Component()) # << previously was self.scene.addItem(Device()) 

Maintenant, les barres de défilement ne semblent pas:
enter image description here

Aussi; lorsque je remplace à la place les lignes suivantes:

LeftMargin = 0 # previously was 50 
RightMargin = 0 # previously was 50 

TopMargin = 0 # previously was 20 
BottomMargin = 0 # previously was 20 

Les barres de défilement n'apparaissent pas. (Je ai probablement franchi une limite avec ces marges ajoutées?)
Je sais que je peux contrôler la politique des barres de défilement avec le QGraphicsView.setHorizontalScrollBarPolicy() pour faire toujours la barre de défilement horizontale, mais cela soulève un autre problème: Quand il n'y a aucun moyen de faire défiler vers la droite, la barre de défilement verticale "vole" certains des pixels de l'affichage, rendant Device.RightMargin != Device.LeftMargin. Aussi, je suis curieux de savoir quelle est la limite de taille au-dessus de laquelle apparaissent les barres de défilement horizontales/verticales.

Donc, c'est la politique que je veux appliquer:

  • Je veux que la zone affichée à toujours avoir une hauteur minimale de pixels X (quelle que soit la hauteur de Device()), et pour la barre de défilement verticale semble que si la hauteur Device() passe ces X pixels limite (je vais déterminer la hauteur de Device() en additionnant tous les Component() hauteurs de)

  • Je veux QGraphicsView de ne jamais montrer barre de défilement horizontale (la largeur 0 La largeur deest fixe et indépendante du nombre de Component() s).

  • Chaque fois que la barre de défilement verticale est nécessaire, je ne veux pas qu'elle prenne des pixels de ma zone d'affichage.
  • Je veux savoir quelle est la limite (en pixels) au-dessus de laquelle les barres de défilement apparaîtront (quand je ne spécifie pas de politique de barre de défilement).

EDIT:
Après avoir joué avec un peu, je me suis dit quelque chose:

  • La barre de défilement horizontale non désirée apparaît seulement parce que l'une verticale apparaît et vole une partie de l'espace d'affichage.

  • Selon le doc, la politique par défaut de la barre de défilement horizontale est Qt::ScrollBarAsNeeded, ce qui signifie: «montre une barre de défilement lorsque le contenu est trop volumineux pour tenir et non autrement », mais il ne dit pas ce est considéré comme "trop ​​grand".
    Lorsque j'ai joué avec les marges (Device.TopMargin/Device.BottomMargin), j'ai découvert que la barre de défilement verticale apparaît (et par conséquent la barre horizontale) lorsque Device.boundingRect().height() franchit la limite des 786 pixels.
    Je n'arrivais pas à savoir d'où venait ce numéro ni comment le contrôler.

+0

786 pourrait provenir de 900 - 100 (barre de titre) - 2 * 7 (bordures de fenêtre), juste une supposition cependant. Ne devrait pas votre exigence "Chaque fois que la barre de défilement horizontale est nécessaire, je ne veux pas qu'elle prenne des pixels de ma zone d'affichage" soit "Chaque fois que la barre de défilement_vertical ..." (la présence d'une barre horizontale a été exclue par la puce précédente point)? Fondamentalement, cela revient à vérifier la présence d'une barre de défilement verticale à chaque redessiner afin d'augmenter la largeur de la fenêtre si nécessaire. Il peut être plus facile d'utiliser des marges gauche/droite asymétriques et afficher la barre de défilement verticale _always_ ... –

+0

Oui, merci, c'est une faute de frappe (horizontale au lieu de verticale). En ce qui concerne votre calcul - comment connaissez-vous ces mesures? (barre de titre, bordures de fenêtre, etc ...) –

+0

De simples suppositions, mais je suis à peu près certaine hauteur de la barre de titre et les bordures de la fenêtre ajouter les 114 pixels manquants de vos 900 pixels hauteur de la fenêtre –

Répondre

3

Je crois que vous cherchez setFixedWidth() et setFixedHeight()

class MainForm(QDialog): 

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

     self.scene = QGraphicsScene(parent) 
     self.view = QGraphicsView(self) 

     self.view.setScene(self.scene) 
     self.scene.addItem(Device()) 
     self.resize(700, 900) 
     self.view.setFixedWidth(650) # <- 
     self.view.setFixedHeight(500) # <- these two lines will set Device dimensions 
     self.setFixedWidth(700)  # <- this will fix window width 

Lorsque vous définissez la largeur fixe view il doit être supérieur à son contenu (marge gauche + Device + marge droite), faites défiler autrement horizontale La barre sera affichée. C'est pourquoi vous n'avez pas obtenu la barre de défilement horizontale lorsque les marges étaient nulles.

Généralement, la barre de défilement apparaît lorsque votre vue actuelle ne peut pas afficher le contenu.

La barre de défilement verticale prendra un peu d'espace à l'intérieur de la fenêtre, et je crois que vous n'avez aucun contrôle sur celle-ci, vous devriez donc réserver une place pour cela. Le comportement de la barre de défilement verticale dépend de votre système Windows, par ex. sur Mac, il plane et disparaît quand il n'est pas nécessaire, donc il ne prend pas de place du tout.

Je recommande de faire la mise en page dans QT Designer. Je trouve cela beaucoup plus facile de le faire visuellement, de le tester immédiatement et d'introduire seulement de petits changements dans le code généré.

+0

Merci. J'ai fini par remplacer 'sizeHint()' par 'return QSize (self.sceneRect(). Width() + 16, self.sceneRect(). Height())'. et définissant la règle de taille horizontale sur "Fixe".(tout nombre inférieur à 16 fait apparaître la barre de défilement verticale pour une raison quelconque), et bien que je déteste utiliser de tels 'nombres magiques' dans mon code, je me convaincs que 16 est exactement la largeur de la barre de défilement verticale (14) + 1 marge de pixels de chaque côté. –

+0

@ donc.vraiment. Pour obtenir la largeur d'une barre de défilement verticale ou la hauteur d'une barre de défilement horizontale, essayez: 'qApp.style(). PixelMetric (QStyle.PM_ScrollBarExtent)'. – ekhumoro