How do I add a QButton on the bottom right corner of a QOpenGLWidget?
The geometry property holds the geometry relative to it's parent excluding frame.
Calculate the position for your child widget relative to the parent widget geometry.
And then set the geometry using setGeometry.
A rough pseudo code is below, (Which is untested and just for Idea. The geometry calculation also may not be correct. But gives you an idea to achieve your goal).
Look into comments for details.
//YOUR OPENGL WIDGET
QOpenGLWidget *pOpenGL = new QOpenGLWidget(<<PARENT WINDOW>>, <<FLAGS>> );
//THE BUTTON YOU ARE TRYING TO ADD. ESTABLISH PARENT CHILD RELATION
QPushButton *pButton = new QPushButton(pOpenGL);
//THIS STEP IS IMPORTANT TO SET THE LOCATION
//CALCULATE THE GEOMETRY POSITION RELATIVE TO PARENT WIDGET
//JUST FOR YOUR IDEA. MAY NEED TO DO SOME PROPER CALCULATIONS
pButton->setGeometry(pOpenGL->x(),pOpenGL->y()-(pOpenGL->height()-20),10,20);
//THEN SET THE CENTRAL WIDGET
setCentralWidget(pOpenGL);
You can use the function move :
QOpenGLWidget *openglWdg = new QOpenGLWidget();
QPushButton * btn = new QPushButton(openglWdg);
btn->move(0 , 0);
Related
Context: I'm making Risk (the popular board game) in C++/Qt, and I've run into a problem. I decided to make the map interactive by placing buttons on every country, which could then be clicked on. After some experimenting, I've subclassed QGraphicsPixmapItem for the buttons, and stuck them inside a QGraphicsScene and a QGraphicsView. I've made the world map a background image via CSS, so that buttons could be overlaid without much hassle.
My problem: I want to place those buttons at specific coordinates. (If it matters, those coordinates would be absolute.) All of the interfaces that I've made so far, I've done in code - I'm not familiar with the Qt Designer, so I'm looking for a function or set of functions that'd let me place my buttons (more or less) where I want them.
What I've tried: I looked in the documentation, but couldn't find a function that let me control where items were placed, just ones that organized items in various ways - columns, horizontal boxes, vertical boxes, etc.
When I designed QWidgets before, I'd done so by placing buttons, other widgets, etc. in QLayouts, but there don't seem to be layouts that allow me the control I'd like. The only one I can see that'd do something similar, is QGridLayout, and experiments with that so far haven't worked the way I wanted them to - the buttons don't get anywhere near the edges of the map, no matter how many columns or rows I add.
The easiest solution would be giving up and placing the buttons beside the map, of course, but that's a last-ditch solution.
Thanks in advance.
EDIT: Added example source code, for clarity.
QHBoxLayout* layout = new QHBoxLayout;
TerritoryButton* test = new TerritoryButton(QPixmap("img.png"));
TerritoryButton* test2 = new TerritoryButton(QPixmap("img.png"));
QGraphicsScene* scene = new QGraphicsScene;
QGraphicsScene* scene2 = new QGraphicsScene;
scene->addItem(test);
scene2->addItem(test2);
QGraphicsView* view = new QGraphicsView(scene);
QGraphicsView* view2 = new QGraphicsView(scene2);
layout->addWidget(view);
layout->addWidget(view2);
setLayout(layout);
setFixedSize(1000, 512);
QGraphicsPixmapItem inherits QGraphicsItem, so you can call setPos(x, y) (after inserting the pixmap item into the scene with addItem).
void QGraphicsItem::setPos(const QPointF &pos)
Sets the position of the item to pos, which is in parent coordinates. For
items with no parent, pos is in scene coordinates.
The position of the item describes its origin (local coordinate (0, 0)) in parent coordinates.
in Qt 4.8 i have create a QGraphicsView and a DynamicRadarScene(derived from QGraphicsScene):
QGraphicsView* view = new QGraphicsView;
view->setMinimumSize(800, 600);
DynamicRadarScene* _scene = new DynamicRadarScene(mode, channel_types, this);
view->setScene(_scene);
What is the coordinate system of QGraphicsScene? (0,0) is from upper left corner?
How can i draw an item in the upper right corner of the scene (i have set it 800x600: view->setMinimumSize(800, 600);)?
If i resize the widget and so i resize the QGraphicsView, how can move the item i have drawn before to remain in the upper left corner?
Yes, the upper left corner is generally the coordinate of (0,0) in a graphics scene. What you need to consider is that a QGraphicsView is like a window looking into a world (the QGraphicsScene). You set the view to look at an area or the scene, which may be all or just part of the scene.
Once the scene and view are setup, you can then add QGraphicsItems / QGraphicsObjects or instances of classes derived from those by using functions such as QGraphicsScene::addItem. These items are positioned in the scene and draw themselves.
i (sic) resize the widget and so i resize the QGraphicsView
You can change the QGraphicsView position and dimensions, but then the items in the scene will remain in the same place within the scene. Usually you would set up the scene and view and then move / resize the graphics items / objects within the scene, often with the setPos function: QGraphicsItem::setPos(). This sets the position of the item, relative to its parent. If the item has no parent, it sets the position of the item in the scene.
QGraphicsScene has property sceneRect. If it is not set then it is auto adjusted depending on scene content. This can give a filling that origin of coordinating is in some strange place or even that it is mobile.
Set this property. See also this.
Whenever I add a new item to a QGraphicsScene, the origin of the QGraphicsScene seem to change for the position of the item I have just added.
How to make the QGraphicsScene origin fixed?
Do I need to add the item first in the QGraphicsScene and then specify a position for the item?
Well, by default the content of the scene will be centered in the QGraphicsView. The origin of the graphics scene does not change randomly.
You might want to use setSceneRect() to define the size of the scene, so that the QGraphicsView always centers the scene in the view in a fixed manner. (If you don't set it manually, the rect will be calculated based on the items in the scene, which changes if you add more.)
I answered a related question about a year ago that may be helpful:
How to draw a point (on mouseclick) on a QGraphicsScene?
Ditto to what badcat.
There are a lot of controls for adjusting or manipulating your viewport(s) that you have pointing at your scene. The scene sets what is on the stage. The view is how you look at it. Be sure to set the sceneRect or set it indirectly using centerOn or fitInView or scale or translate from the QGraphicsView class.
http://qt-project.org/doc/qt-4.8/graphicsview.html
http://qt-project.org/doc/qt-4.8/qgraphicsview.html
QGraphicsScene::setSceneRect ( const QRectF & rect ) will make it absolute.
see http://doc.qt.digia.com/qt/qgraphicsscene.html#sceneRect-prop
I have a QMainWindow whose central widget has been set to a QGraphicsView viewing a black scene (for test purposes). Note that in the code below, I use my class derived from QGraphicsView, called CQtGlView, which reimplements only the resizeEvent function.
Regardless of whether I add the view directly,
CQtMainWindow::CQtMainWindow() {
m_glView = new CQtGlView();
setCentralWidget(m_glView);
}
or stick it in a layout with margins of 0 in a dummy widget,
CQtMainWindow::CQtMainWindow() {
m_glView = new CQtGlView();
QWidget* dummy = new QWidget();
QHBoxLayout* l = new QHBoxLayout();
l->setContentsMargins(0,0,0,0);
l->addWidget(m_glView);
dummy->setLayout(l);
setCentralWidget(dummy);
}
I get an unwanted grey border around the widget.
The screenshot below illustrates the problem, visible between my scene and the windows aero border.
This would not be a problem if my application did not allow switching to full screen. The border is very obvious once the rest of the screen is black.
It's possible this area represents the DockWidgetAreas around the outside of the central widget.
Is there anything I can do to solve this other than not use QMainWindow? (Undesirable due to my use of menuBar, tool bars, and statusBar.)
It turns out that QGraphicsView derives from QFrame, where I assumed it was only a QWidget.
The solution to this problem was to call setFrameStyle(QFrame::NoFrame); in the constructor of my QGraphicsView subclass. Or if it was not a subclass,
m_glView->setFrameStyle(QFrame::NoFrame);
Have you tried setFrameShape(QFrame::NoFrame) on the QGraphicsView?
Use case: This should be a fairly common problem. In a normal QMainWindow with QMdiArea lives an mdiChild with a QGraphicsView. This view displays a QGraphicsScene with QGraphicsItems inside. A right-click at one of these items selects (focusses) the item and opens a context menu, which is conveniently placed at the screen coordinates QGraphicsSceneMouseEvent::screenPos(). This is working as expected.
Now I'd like to show the same context menu when the user presses a key (e.g. Qt::Key_Menu). I know the selected (focussed) item, I know the view which displays the scene.
So my question is:
What is the correct way to get the position (in global, screen coordinates) of the visible representation of a QGraphicsItem within a scene?
Here is what's not working:
QGraphicsItem *item = ...; // is the currently selected item next to which the context menu shall be opened
QGraphicsScene *scene = ...; // is the scene that hosts the item
QGraphicsView *graphicsView = ...; // is the view displaying the scene, this inherits from QWidget
// get the position relative to the scene
QPointF sp = item->scenePos();
// or use
QPointF sp = item->mapToScene(item->pos());
// find the global (screen) position of the item
QPoint global = graphicsView->mapToGlobal(graphicsView->mapFromScene(sp));
// now
myContextMenu.exec(global);
// should open the context menu at the top left corner of the QGraphicsItem item, but it goes anywhere
The doc says:
If you want to know where in the viewport an item is located, you can call QGraphicsItem::mapToScene() on the item, then QGraphicsView::mapFromScene() on the view.
Which is exactly what I'm doing, right?
Just stumbled upon a thread in a german forum that hints to:
QGraphicsView *view = item->scene()->views().last();
or even nicer:
QGraphicsView *view;
foreach (view, this->scene()->views())
{
if (view->underMouse() || view->hasFocus()) break;
}
// (use case in the forum thread:) // QMenu *menu = new QMenu(view);
Using that might allow a more generalized answer to my question...
I found a working solution.
The QGraphicsItem must be visible on the screen.
(Probably if it's not visible because the view shows some other point of the scene, one could restrain the point to the view's viewport's rect.)
// get the screen position of a QGraphicsItem
// assumption: the scene is displayed in only one view or the first view is the one to determine the screen position for
QPoint sendMenuEventPos; // in this case: find the screen position to display a context menu at
QGraphicsItem *pFocusItem = scene()->focusItem();
if(scene() != NULL // the focus item belongs to a scene
&& !scene()->views().isEmpty() // that scene is displayed in a view...
&& scene()->views().first() != NULL // ... which is not null...
&& scene()->views().first()->viewport() != NULL // ... and has a viewport
)
{
QGraphicsView *v = scene()->views().first();
QPointF sceneP = pFocusItem->mapToScene(pFocusItem->boundingRect().bottomRight());
QPoint viewP = v->mapFromScene(sceneP);
sendMenuEventPos = v->viewport()->mapToGlobal(viewP);
}
if(sendMenuEventPos != QPoint())
{
// display the menu:
QMenu m;
m.exec(sendMenuEventPos);
}
It is important to use the view's viewport for mapping the view coords to global coords.
The detection of the context menu key (Qt::Key_Menu) happens in the keyPressEvent() of the "main" QGraphicsItem (due to the structure of my program).
The code seems to be correct. But there might be some problem with the creation of the context menu.
Have you set the parent of the QContextMenu to MainWindow (or something of that sort in your application)??
I think that might be the problem in your case.
Good Luck!!
Just a stab in the dark but have a look at this http://www.qtcentre.org/threads/36992-Keyboard-shortcut-event-not-received.
On looking through the Qt documentation, it seems the use of QGraphicsView may cause some exceptional behaviour with regards to shortcuts.
It looks as if there might be a normative way of achieving the result you desire.
Depending how you are implementing your context menu, shortcuts and QGraphicsView, you might need to set the Qt::ContextMenuPolicy for the QGraphicsView appropriately and build and call the menu differently.
I'm quite interested in this question as I will need to do something quite similar shortly!