2

I have a QMainWindows with inside a QGraphicsView that takes all the client area. Inside the view I render some QGraphicsTextItem items. Everything works as long as I don't resize the main window. If I do it, the items stay where they were and don't move to the new correct position. Basically what I would do is having a behaviour like in the layout widgets that expands if needed

UPDATE 1

enter image description here

UPDATE 2enter image description hereenter image description here

UPDATE 3

with the following code the buttons are positioned at the right side of the client area. 944 is the width defined from the Qt Designer of the QGraphicsView. I have the same code for the widgets at the left of the area, starting xPos from 10 and incrementing it every time I add a new button. If I resize the window the left widgets always shift to the new position, the right doesn't have the same behaviour. Why?

this->ui.setupUi(this);

qreal xPos = 944 - 10;

QGraphicsTextItem *myButton1 = new QGraphicsTextItem("my text");

myButton1 ->adjustSize();
myButton1 ->setPos(xPos - myButton1 ->textWidth(), 10);

xPos -= myButton1 ->textWidth();

this->m_graphicsScene->addItem(myButton1);


QGraphicsTextItem *myButton2 = new QGraphicsTextItem("my text 2");

myButton2 ->adjustSize();
myButton2 ->setPos(xPos - myButton2->textWidth(), 10);

xPos -= myButton2 ->textWidth();

this->m_graphicsScene->addItem(myButton2);
Stefano
  • 3,213
  • 9
  • 60
  • 101
  • It is not clear exactly what should happen. Should the display be scaled? Should some magic "relayout" happen, i.e. an item that was centered needs to stay centered but keep its geometry? – Mat May 27 '12 at 10:40
  • as you can see in the screenshot there are some things at the right of the client area. If I resize the window the things doesn't move right but stay in the old position. – Stefano May 27 '12 at 11:27
  • What about the other stuff in the view? I suspect you don't want everything shifted to the left of the view. Please be more descriptive. – Mat May 27 '12 at 11:28
  • I basically would have some layout that stretch if needed (like the QGridLayout). Things positioned in the left area of the client when the window is resized go to the new position but things that I drawn on the right area are not shifted to their new position. – Stefano May 27 '12 at 11:30
  • I'm sorry that makes no sense. If things drawn on the right are not shifted, you'll have what you have in your screenshot (i.e. stay in the middle). You're talking about resizing now? So some scaling needs to be applied? Please do a real mockup of what you want to happen, and please show what you have tried so far to solve this yourself. – Mat May 27 '12 at 11:32
  • I tried to explain better with some images. As you can see after a resize of the QMainWindow the widgets on the left always stay at P(10, 10) from the top left corner of the client area but the widgets on the right that should be at clientarea.width - 10 stay on a fixed position and are not moved along with the new window size to always stay at the same distance from the top right corner – Stefano May 27 '12 at 11:43
  • Ok, this is starting to make sense. Now, what have you tried so far? Where's your code? – Mat May 27 '12 at 11:45
  • I've added the code that I currently have. I think the problem could be because i'm using a fixed width (944) instead of using some dynamic property like QGraphicsView::width(). At the moment I don't have any idea about how to fix my problem, I'm quite new to Qt and searching on google didn't help me – Stefano May 27 '12 at 11:52
  • Are you sure a qgraphics approach is even the best choice for this? How did you decide you need a scene as opposed to a standard qwidget approach? – jdi May 27 '12 at 17:07
  • I'm starting to think it's not the best approach. I was searching something that allow me to style all the controls in the way I want, removing margins, paddings and everything else. It seems also that QGraphicsScene is more precise in drawing an object in a specific position while the normal Qt Designer seems that doesn't love "pixel-based" positions. Correct me if I'm wrong – Stefano May 27 '12 at 17:12
  • @jdi I forgot to add the most important thing: I want a fluid interface, so with animations, etc – Stefano May 27 '12 at 17:27
  • QWidgets are integer based pixels. QGraphicsScene uses floats. You can animate both widgets and graphics. You can also style qwidgets however you want. QGraphics is good when you want a lot of custom objects, or very complex displays or interfaces. – jdi May 27 '12 at 17:29
  • with QGraphicsScene I can place everything I want on the area in a pixel-based mode. Can I do the same with the Qt Designer? It seems no, you must use layouts that can't be placed in the way you want because they stretch without having the control on how they should do it. – Stefano May 27 '12 at 18:04

1 Answers1

3

The QGraphicsView has no directly connection to the QGraphicsItem objects inside of the scene. Its only purpose is to visualize a slice of your scene in a viewport, and transmit user interactions to the scene. There are no layouts, however layouts were added to be used with QGraphicsWidget (but that is a special needs case). Regardless, this is simply related to the translation of the view, as opposed to the position of the items in the scene (completely unrelated to each other)

What you will most likely need to do, is subclass QGraphicsView, and re-implement resizeEvent in your view: http://qt-project.org/doc/qt-4.8/qgraphicsview.html#resizeEvent
In the resizeEvent, you would translate the view by an amount based on the resize: http://qt-project.org/doc/qt-4.8/qgraphicsview.html#translate

Essentially, you are creating your own layout manager functionality within your custom QGraphicsView.

Update

I realize what you mean, that when the sceneRect is larger than the QGraphicsView, it will use scrollbars and not keep your view centered on resize. Ideally, if you are creating the type of graphics scene where the content doesn't need to scroll, you should leave the sceneRect default, or set it to the size of the viewport.

Otherwise, here is a really basic example of how you would use the resizeEvent. This is in PyQt but I am sure you can translate:

class Dialog(QtGui.QDialog):

    def __init__(self):
        super(Dialog, self).__init__()
        self.resize(640,480)
        layout = QtGui.QVBoxLayout(self)

        self.scene = QtGui.QGraphicsScene(self)
        self.scene.setSceneRect(-500,-500,1000,1000)
        self.view = GraphicsView(self)
        self.view.setScene(self.scene)
        layout.addWidget(self.view)

        text = self.scene.addText("Foo")

        self.view.updateCenter()


class GraphicsView(QtGui.QGraphicsView):

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

    def resizeEvent(self, event):
        super(GraphicsView, self).resizeEvent(event)
        if self._center:
            self.centerOn(self._center)

    def updateCenter(self):
        center = self.geometry().center()
        self._center = self.mapToScene(center)

It saves the scene point you are interested in when you call updateCenter(). Then, every time your view resizes, it will center back to that scene point.

Update 2: After your picture posts and updates

If you really need this kind of normal QWidget behavior in a QGraphicsScene, with layouts, then you should be looking at QGraphicsWidgets, which do support layouts. Then you can make one large root "canvas" widget, and make everything else a child of that, inside of layouts. Then you only need to worry about keeping the root widget sized properly. You would then be able to use the same example above to manage the size and position of your root widget.

Refer to this question for more details since its the same situation of someone wanting to integrate a QGraphicsItem into layouts:
QGraphicsWidget vs. QGraphicsLayoutItem

Community
  • 1
  • 1
jdi
  • 90,542
  • 19
  • 167
  • 203
  • could you please write me a very little example showing how to implement the translate function? After this I will accept your answer – Stefano May 26 '12 at 23:31
  • @Stefano: What version of Qt are you using? I actually went to make an example and realized that the default behavior of the view is to keep the relative positions. That is, if I make a text item at the center of the scene, and resize the view, it stays in the center as the view grows. I think you will need to post a very short working example that shows the problem. – jdi May 26 '12 at 23:44
  • That is exactly the problem. I'm using qt 4.8 on windows. I place for example a QGraphicsTextItem at position 0, 100. After that I resize the window: the item should move and keep still the same position also if the window grow but in my case it simple does nothing – Stefano May 26 '12 at 23:53
  • @Stefano: This behavior only occurs if your sceneRect is larger than your view. If you set your scene rect to the same size as the view (or don't set it at all), it will keep everything centered. – jdi May 27 '12 at 00:10
  • I think I explained badly my problem. I don't want that the widgets stay in center, I want that when I resize the window the widgets follow the width/height and so if they were at the top left after the resize must still be at the top left. This not happens, they stay at a fixed position – Stefano May 27 '12 at 08:06
  • @Stefano: Thats fine, but I think my example still gives you the right direction. This example shows how to keep it centered. You can use other properties of the scene, or the view size to translate The objects you want to where they need to go – jdi May 27 '12 at 14:15
  • @Stefano: you will need to subclass your own or compose it in a QGraphicsWidget. – jdi May 27 '12 at 17:30