How do I set a relative position for a Qt widget? - qt

I've been searching around and reading docs about moving widgets around, but I'm still looking for a good example.
I have a widget that I display with a hotkey, and I'd like it to popup somewhere else in the MainWindow rather than the center. If I use move(), then the widget remains in that position regardless if it's parent window changes position. I'd like the widget to be placed in a location inside of the parent widget so that when moving the parent widget, it stays in the relative position. How can I go about doing this?
I read about MapToParent, but I'm not sure how to use this. I tried:
QPoint fD_p = fDialog->pos();
QPoint parent_fD_p = QWidget::mapToParent(fD_p);
fDialog->move(parent_fD_p);

You should reimplement the move event handler in your parent widget void QWidget::moveEvent ( QMoveEvent * event ) and probably the resize event handler.
In these event handlers you can recalculate the new position for your widget and then move it.
mapToParent and mapFromParent methods translate relative coordinates. From the documentation:
QPoint QWidget::mapFromParent ( const QPoint & pos ) const
Translates the parent widget coordinate pos to widget coordinates.
Same as mapFromGlobal() if the widget has no parent.

Related

setParent() not showing child widget

I have a class called TitleBar inherited from QWidget and I created a new widget and did setparent() but after doing setparent child widget is not showing, it is showing only after commenting setparent but not alligned with parent, its displaying in some random placess, On maximized view only it shows on right place
TitleBar::TitleBar(QWidget *parent) : QWidget(parent)
{
m_jobSubmitWidget = csJobSubmitPoolWidget::getSubmitPoolInst();
// m_jobSubmitWidget->setParent(QWidget::window());
}
void csTitleBar::BtnClicked()
{
QPoint pos = m_queueBtn->pos() + m_serverToolBar->pos() + QPoint(-m_jobSubmitWidget->width() + m_queueBtn->width(),62); // these are member variables in TitleBar class
// pos shows always same value on moving parent widget
if(itemCount > 2){
m_jobSubmitWidget->move(pos);
m_jobSubmitWidget->show();
m_jobSubmitWidget->setFocus();
}
}
I really suggest that you take a good read at Qt documentation.
QWidgets that have a parent are displayed inside their parent (except for QDialog). If a widget does not have a parent, it will be shown as a separate window.
Parenting a widget to the result of QWidget::window() is kind of hazardous as you don't really know which widget will be returned, so you do not know where the child widget will end up.
Also you do not need to call show() on widgets that have a parent. By default their visibility follows the parent visibility.
In my case I also had to add the widget which I was changing the parent (here textEdit) to the target containing layout:
ui->textEdit->setParent(ui->groupBox1);
m_lastVboxLayout->removeWidget(ui->textEdit);
m_lastVboxLayout = ui->verticalLayout_groupBox1;
m_lastVboxLayout->addWidget(ui->textEdit);
no need to call show() afterwards.

Move QGraphicsItem with mouse hover

I'm trying to move a QGraphicsItem with the mouse hover over the parent item.
BaseItem::BaseItem(const QRectF &bounds)
: theBounds(bounds), theMousePressed(false)
{
theLineItem = new LineItem(theBounds, this);
setAcceptHoverEvents(true);
}
and
void BaseItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
QPointF position = mapToScene( event->pos());
theLineItem->setPos( position);
}
But the item is not moving. Is there any other way to move the item on the scene with mouse move, without using the ItemIsMovable flag, because I want the item to be moved around the parent item, once it's invoked?
When you create the LineItem, in its constructor you pass the BaseItem as the parent.
A call to setPos on a GraphicsItem, sets the position of the item relative to its parent which, in this case, is the BaseItem.
Mapping the event->pos() to scene coordinates is wrong here. event->pos() returns the position in local coordinates of the receiving object, which in this case is the BaseItem.
Therefore, you should be setting the position of theLineItem directly with event->pos().
theLineItem->setPos(event->pos());
Note that if you did happen to want the event position in scene coordinates, there's a function already available: -
event->scenePos();
So you would not have needed to call mapToScene.

How to display fix banner between QMenubar and QToolBar in QMainWindow

How can I show fixed banner (with some widget like label and button ) in between
QMenuBar and QToolBar ?
Similarly like QStatusBar but in between QMenuBar and QToolBar.
I tried to implement using QToolBar.
// toolbar Banner with lable inside it.
QLabel * bannerLabel = new QLabel(" bannerToobar with label banner.");
bannerLabel->setAlignment( Qt::AlignVCenter );
ui.bannerToobar->addWidget( bannerLabel );
ui.bannerToobar->setAllowedAreas(Qt::ToolBarArea::TopToolBarArea);
ui.bannerToobar->setMovable( false );
QSize banner_sz = ui.bannerToobar->size();
ui.bannerToobar->setFixedHeight( banner_sz.height() * 2 );
QSizePolicy banner_szPolicy( QSizePolicy::Policy::Maximum, QSizePolicy::Policy::Fixed );
banner_szPolicy.setHorizontalStretch(255);
ui.bannerToobar->setSizePolicy( banner_szPolicy );
but i can't prevent user from draging mainToolbar and droping in the same row as my
bannerToolbar
You can force it to wrap initially using QMainWindow::addToolBarBreak, but I don't know a way to prevent it from being put back there later by the user (except for making the toolbars non-moveable).
If there was a QToolbar::dockLocationChanged signal (which seems to have been requsted and resolved in https://bugreports.qt-project.org/browse/QTBUG-1274, but I still don't see the signal anywhere), I suppose you could use insertToolBarBreak to fix it up whenever things have changed. Maybe there's some hackish way you could get notified when the toolbars move.
Or you could use QMainWindow::setMenuWidget to place a widget containing both your QMenuBar and something else into the menu area of the QMainWindow. This could get tricky if you want to support styles (mac/gnome/etc) where the menubar gets lifted out of your window to the top-of-screen and the toolbar gets unified with the window title decorations. But the idea of a banner between menubar and toolbar just naturally has problems in such cases :-)

Moving a QPixmap to the corner of a QGraphicsScene

I have a QGraphicsView and a QGraphicsScene connected like this:
graphicsScene->setSceneRect(this->graphicsView->rect());
graphicsView->setScene(this->Scene);
Then I load an image and add it to the scene:
QPixmap pixmap;
pixmap.load(fileName);
pixmap = pixmap.scaled(this->graphicsView->size());
QGraphicsPixmapItem* item = this->Scene->addPixmap(pixmap);
Now, as described in the documentation, the image corner is at (0,0), which is not the corner of the graphicsScene. I know I can position the resulting pixmap by doing:
item->setPos(this->Scene->sceneRect().x(), this->Scene->sceneRect().y());
However, I can't seem to make sense of the coordinates of the rect's of the scene or the view. Can anyone explain how I would move the pixmap to the corner of the scene/view?
Thanks,
David
EDIT: Here is the full form constructor. The QGraphicsView was created in Qt Designer and is inside of a GridLayout:
Form::Form(QWidget *parent)
: QWidget(parent)
{
setupUi(this);
QGraphicsScene* scene = new QGraphicsScene;
scene->setSceneRect(this->graphicsView->rect());
this->graphicsView->setScene(scene);
QPixmap pixmap;
pixmap.load("image.png");
pixmap = pixmap.scaled(this->graphicsView->size());
scene->addPixmap(pixmap);
}
I also tried this:
QGraphicsScene* scene = new QGraphicsScene;
this->graphicsView->setScene(scene);
QPixmap pixmap;
pixmap.load("/home/doriad/glasses.jpg");
QGraphicsPixmapItem * item = scene->addPixmap(pixmap);
this->graphicsView->fitInView (item);
but the image appears tiny, rather than filling up the view like I would expect. Can anyone explain this?
The full project and image are available here: daviddoria.com/Uploads/qt/QPixmapPosition
Don't worry about scaling the pixmap yourself or even translating it, let the view do it for you.
Use graphicsView->fitInView(pixmap); but you should read the documentation for :
Qt's Graphics View Framework
void QGraphicsView::setSceneRect (QRectF )
void QGraphicsView::translate ( qreal dx, qreal dy )
void QGraphicsView::fitInView ( const QGraphicsItem * item, ... )
The way that QGraphicsScene and QGraphicsView interact is that you can have a single scene with at least one or more views.
A good example I like to think of is a zoomed in view of part of a map with a mini view of the entire map in the corner. There are two views, one of part of the map and one of the entire map, with one scene, the map itself.
So you put items in your scene and all the items in the scene are drawn relative in size to each other. The "scene rect" of your view, by default, scales to fit the items in the view until one unit in the scene is one pixel in the view or until it needs to zoom out to fit all the items in your scene.
If you call fitInView(someItem) it should scale your view of the scene so that the item specified fills it up and translates the view so that it is centered. If you need to translate or scale it more use the translate or scale functions in QGraphicsView.
When you are jumping between coordinate systems of your scene and view with your QRect's or QPoint's, use the helper functions: mapToScene and mapFromScene from QGraphicsView.
Try this:
QGraphicsScene* scene = new QGraphicsScene;
scene->setSceneRect(graphicsView->sceneRect());
QPixmap pixmap;
pixmap.load("/home/doriad/glasses.jpg");
pixmap=pixmap.scaledToWidth(this->graphicsView->width());
QGraphicsPixmapItem * item = scene->addPixmap(pixmap);
graphicsView->setScene(scene);
By default, the pixmap will be at (0,0) in the scene, and the scene will be at (0,0) in the view. QWidgets are sized by pixels. If you had a QGraphicsView the size of the screen and the resolution is 1440 x 900, you can position objects in that view from (0,0) or the top left corner of the screen, to (1440,900) the bottom right corner of the screen. Most QGraphicsItems are placed with reference to their top left corner. So placing a pixmap at (0,0) aligns the top left corner of the pixmap with the top left corner of the scene it's placed in. If your pixmap 'hangs off the bottom' of your view, try using:
pixmap=pixmap.scaledToHeight(this->graphicsView->height());
If you use the function:
this->graphicsView->fitInView (item);
The graphicsView will only scroll to the point where your item fits in the view.
I downloaded David's code and ran it two ways. Click the links to see the results.
1) with pixmap=pixmap.scaledToHeight(this->graphicsView->height());
2) with pixmap=pixmap.scaledToHeight(200);
I don't know enough to explain why this is happening, but I thought it would be a useful data point.
It turns out the problem was that the GraphicsView was in a layout. In my example, the resizing of the image was done in the Form constructor. Apparently this is before the layout takes its shape? I moved the code to a pushButton and when I click it the image is sized how I would expect.
I got the image to stay sized to the GraphicsView in the Layout by subclassing QGraphicsView and reimplementing :
class CustomGraphicsView: public QGraphicsView
{
Q_OBJECT
{
void resizeEvent ( QResizeEvent * event )
{
emit resized();
}
signals:
void resized();
}
Then I connect this resized() signal to a slot that simply calls this->View->fitInView (this->ImageToTraceItem);
David

How to hide a QWidget under its parent?

I have a modal QDialog, that on the click of a button slides a modeless child QDialog out from underneath it. The problem I have is that the child stays on top of its parent during the animation.
I think I could get away with applying a mask over the portion of the child that overlaps the parent, but it feels like I'm missing a more obvious way of just placing the child under the parent.
I'm using Qt 4.5. Here's some sample code:
void MainWindow::on_myMenu_triggered()
{
parentDlg = new QDialog(this);
parentDlg->setFixedSize(250, 250);
parentDlg->setModal(true);
parentDlg->show();
childDlg = new QDialog(parentDlg);
childDlg->setFixedSize(150, 150);
childDlg->show();
QTimeLine* timeLine = new QTimeLine(1000, this);
connect(timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(childDlgStepChanged(qreal)));
timeLine->start();
}
void MainWindow::childDlgStepChanged(qreal)
{
int parentX = parentDlg->frameGeometry().x();
int parentY = parentDlg->geometry().y();
// Move the child dialog to the left of its parent.
childDlg->move(parentX - 150 * step, parentY);
}
Thanks in advance.
Child widgets are always rendered over the parent so you would have to break that relationship in order to achieve the affect you are looking for directly. Then you could use raise() or lower() if both dialogs had the same parent.

Resources