Dragged QGraphicsItem not visible in items() function - qt

I have created a QGraphicsScene scene and added some graphcis items (lines, rectangles) etc to the scene.
I can loop through them using this list :
QList<QGraphicsItem*> all = items();
I enabled movement for these items and I am able to drag them by click selecting them. But after an element has been dragged, it stops showing up in the call to items() function of the QGraphicsScene.
QList<QGraphicsItem*> all = items();
None of the dragged items show up in the above list, while non-dragged ones do show up.
Does dragging the QGraphicScene elements change their parent ? or any other reason somebody could suggest for such an issue ?
{P.S. Code is too very big to share}
Edit 1 :
I am using the flags QGraphicsItem::ItemIsSelectable and QGraphicsItem::ItemIsMovable for making the items movable.
foreach(QGraphicsItem* itemInVisualScene, items())
{
itemInVisualScene->setFlag(QGraphicsItem::ItemIsSelectable, itemsMovable);
itemInVisualScene->setFlag(QGraphicsItem::ItemIsMovable, itemsMovable);
}
By default I add few rectangle to the scene. Then in the 'move mode' I drag them around. Then in the 'add mode' I click on screen to add new rectangles. I have written a logic to check if I am clicking on any existing drawn rectangle :
void Scene::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
if(eDrawLines == sceneMode)
{
dragBeginPoint = event->scenePos();
dragEndPoint = dragBeginPoint;
QList<QGraphicsItem*> all = items();
for (int i = 0; i < all.size(); i++)
{
QGraphicsItem *gi = all[i];
// Clicked point lies inside existing rect
if( QGraphicsRectItem::Type == gi->type() && gi->contains(dragBeginPoint))
{
std::cout << "Pressed inside existing rect" << std::endl;
return;
}
}
std::cout << "Point not found, add new rectangle" << std::endl;
}
QGraphicsScene::mousePressEvent(event);
}
This adding of rectangles work fine for rects which were not dragged in the 'move mode'. But rects which were moved do not seem to recognize the click anymore. My control comes out of the loop even when I click on an existing rectangle which was dragged earlier.

QGraphicsItem's transform is changed after dragging and therefore need to transform the point to item's local coordinates.
gi->contains(gi->mapFromScene(dragBeginPoint))
To convert or get item's position in scene coordinates, use
gi->mapToScene(0,0) or gi->scenePos()

Related

How to get minimize/restore/close rectangle?

I want to draw some text in the end of menu bar like this
But when the child window is maximized in the MDI project it looks like this
I need to fix this output.
I want to check if the active child is maximized and if it is I want to get minimize/restore/close rectangle to get them total width.
How can I get active child window and how can I get it's rectangle of buttons?
// in yourMainWindow.cpp
...
auto child = mdiArea->addSubWindow(yourWidget);
connect(child, &QMdiSubWindow::windowStateChanged, this, &yourMainWindow::yourSlot);
...
void yourMainWindow::yourSlot(Qt::WindowStates oldState, Qt::WindowStates newState)
{
if (newState.testFlag(Qt::WindowMaximized)) {
auto child = qobject_cast<QMdiSubWindow *>(sender());
if (!child)
return;
QStyleOptionComplex opt;
opt.initFrom(child);
auto size = child->style()->sizeFromContents(QStyle::CT_MdiControls, &opt, QSize(100, 20));
qDebug() << size;
}
}

Qt: Visibility state of the QWidget when used stylesheet

I have customized QWidget named "MainWidget" and a customized QWidget named "ChildWidget".
MainWidget is the parent of ChildWidget and these child widgets are created dynamically and inserted into the MainWidget's stack of widgets.
I have used style sheet to set the background color of the both MainWidget and ChildWidget in their respective .ui (form) file.
Select the widget ->Right Click on Widget-> Change stylesheet -> select background color-> apply -> save the .ui file
"background-color: ;"
Each ChidlWidget has its own unique size (width & height) such that when they have stacked on MainWidget's stack of widgets, there may be chances of one widget overlapping other widget, some widgets are completely obscured and some widgets are partially visible.
I am trying to find the visibility state of all types of widgets ( obscured, completely visible , partially visible) .
I am using following code snippet.
void MainWidget::printVisibilityState()
{
QList<ChildWidget *> childWidgetsList = findChildren<ChildWidget *>();
for (register int i = 0; i < childWidgetsList.size(); i++)
{
ChildWidget* pWidget = childWidgetsList.at(i);
QRegion visibleRegion = pWidget->visibleRegion();
QRect visibleRegionBoundingRect = visibleRegion.boundingRect();
int visibleRegionRectsCount = visibleRegion.rects().count();
QRect widgetRect = pWidget->rect();
if (visibleRegion.isEmpty()) {
qDebug() <<pWidget->getName()<< "is OBSCURED";
}
else {
if (
(visibleRegionBoundingRect == widgetRect) &&
(1 == visibleRegionRectsCount))
{
qDebug() <<pWidget->getName()<< "is VISIBLE";
}
else
{
qDebug() <<pWidget->getName()<< "is PARTIALLY VISIBLE";
}
}
}
}
and I have implemented painEvent in both MainWidget and ChildWidget with the following code snippet.
void ChildWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
void MainWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
This code prints the visibility state for all child widgets as VISIBLE always.
Note: Instead of setting the background-color using style sheet, if I use the setAutoFillBackground(true) for both MainWidget and ChildWidget then I am getting the proper visibility state.
Could you please guide me why it doesn't get me the proper visibility state when used style sheet?
Am I missing something in calculating the visibility state?
Are there any other way to get the visibility state info?
The QWidget document (http://qt-project.org/doc/qt-4.8/qwidget.html#visible-prop) says that, "A widget that happens to be obscured by other windows on the screen is considered to be visible."
If this is the case How do we determine the visibility state for the partially visible widgets? ( For example an error popup on other window, so error popup is completely visible and window is partially visible)
Please help me
Regards
SRaju

(Qt) Rendering scene, different items in the same relative positions

I have a QSqlTableModel model that contains my data.
I have made a QGraphicsScene scene and a QGraphicsView view so the user can move around same myQGraphicsTextItem text items until the desired position.
Something like this:
myQWidget::myQWidget()
{
//these are member of my class
chequeScene = new QGraphicsScene();
chequeView = new QGraphicsView();
model = new QSQLTableModel();
//populate model, inialize things here...
//add predefined items to the scene
setScene();
}
there's a button to show the view and move the textitems of scene. It works well.
there's a button that calls the slot print that belongs to the class. It configures a QPrinter and then calls the following paint method myQWidget::paint(), after that scene->render() is called.
The porpoise of the method below is to print data on a paper that is configured to have the same size than the scene while printing the data in the same relative position the textItem had on the scene. Can't do it with QList it doesn't order the items in the same way I added them to the scene.
Here is my code below, it prints with overlapping of some fields doe to QList order items as they appear on the scene.
void myQWidget::paint()
{
qreal dx = 0;
qreal dy = 0;
QList<QGraphicsItem*> L = chequeScene->items();
for (int j=0; j<model->columnCount(); j++) {
if(!L.isEmpty())
{
//Saves the position on dx, dy
dx = L.first()->scenePos().x();
dy = L.first()->scenePos().y();
chequeScene->removeItem( L.first() );
delete L.first();
L.removeFirst();
}
QString txt("");
//selecting printing formar for each column
switch(j)
{
case COLUMNADEFECHA:
txt = QDate::fromString(model->data(model->index(chequenum,j)).toString(), "yyyy/MM/dd").toString("dd/MM/yyyy");
break;
case COLUMNADECHEQUES:
break;
default:
txt = model->data(model->index(chequenum,j)).toString();
break;
}
//filtering not important columns
if(j!=COLUMNADECHEQUES)
{
//Supposubly item with the desired information is added to the scene
//on the same position it had before. Not working.
GraphicsTextItem *item=new GraphicsTextItem();
item->setPlainText(txt);
item->setPos(dx,dy);
chequeScene->addItem(item);
}
}
}
Any idea on how to get this working?
I think as you are getting the scenePos in dx and dy but are setting it using setPos function.
Also as you are using your GraphicsTextItem and not QGraphicsTextItem maybe a look at your paint method will help in understanding the problem.
Try using item->mapFromScene(dx, dy) and then use those coordinates to set the item position by item->setPos(..).
Hope This Helps..

Items in a QGraphicsScene near the mouse

I am trying to find the items under the mouse in a scene. The code I am using is as follows:
QPainterPath mousePath;
mousePath.addEllipse(mouseEvent -> pos(),5,5);
QList<QGraphicsItem *> itemsCandidate = this->items(mousePath);
if (!(itemsCandidate.contains(lastSelectedItem))) lastSelectedItem =itemsCandidate.first();
PS: this refers to a scene.
The code should find the items intersected by a small circle around the mouse position and keep the item pointer unchanged if the previous intersected one is still intersected, or take the first in the QList otherwise.
Unfortunately, this code does not work with items inside each other. For example, if I have a Rect side a Rect, the outer Rect is always intersecting the mouse position even when this one is near the inner Rect. How can i solve this?
UPDATE: This seems not to be a problem with polygons, but with Rect, Ellipses, etc.
UPDATE: This code is in the redefined scene::mouseMoveEvent
You can reimplement ‍mouseMoveEvent in ‍QGraphicsView‍ to capture mouse move events in view and track items near the mouse like:
void MyView::mouseMoveEvent(QMouseEvent *event)
{
QPointF mousePoint = mapToScene(event->pos());
qreal x = mousePoint.x();
qreal y = mousePoint.y();
foreach(QGraphicsItem * t , items())
{
int dist = qSqrt(qPow(t->pos().x()-x,2)+qPow(t->pos().y()-y,2));
if( dist<70 )
{
//do whatever you like
}
}
QGraphicsView::mouseMoveEvent(event);
}

Displaying image as background of QGraphicsScene

I try to use QGraphicsView to display a map with some QGraphicItem-subclass showing region centers of the map. Conceptually, I organize the map as follow:
QGraphicsView
QGraphicsScene
QGraphicsPixmapItem : background image, fixed until next call of loadSetting
QGraphicsRectItem : legend, position relative to bg is fixed throughout app
QGraphicsEllipseItem : region centers
I want the map to behave as follow:
no scrollbars to be displayed, and the background image fillup all the visible area of the view/scene.
when the widget is re-sized, the QGraphics*Items will re-size themselves accordingly (as if the view is zoomed)
relative positions of QGraphicsEllipseItems, remain fixed until next call of loadSetting()
Now I have problem in getting the background image displayed properly.
Constructor [I'm adding this view to a QTabWidget directly: myTab->addTab("name", my_view_); ]
MyView::MyView(QWidget *parent) : QGraphicsView(parent) {
bg_pixmap_ = new QGraphicsPixmapItem();
legend_ = new MapLegend();
setScene(new QGraphicsScene(this));
scene()->addItem(bg_pixmap_);
scene()->addItem(legend_);
}
Load map setting (during program execution, this method may be invoked multiple times)
void MyView::loadSetting(Config* cfg) {
if (!cfg) return;
/* (a) */
scene()->clearFocus();
scene()->clearSelection();
for (int i = 0; i < symbols_.size(); i++)
scene()->removeItem(symbols_[i]);
qDeleteAll(symbols_);
symbols_.clear();
/* (a) */
/* (b) */
background_ = QPixmap(QString::fromStdString(cfg->district_map));
bg_pixmap_->setPixmap(background_);
for (size_t i = 0; i < cfg->centers.size(); i++) {
qreal x = cfg->centers[i].first * background_.width();
qreal y = cfg->centers[i].second * background_.height();
MapSymbol* item = new MapSymbol(x, y, 10);
symbols_.append(item);
scene()->addItem(item);
}
/* (b) */
update();
}
Questions
Now all items except the 'bg_pixmap_' got displayed, and I checked the 'background_' variable that it loads the image correctly. Is there anything I missed?
How do I implement the resizeEvent of MyView to cope with the desired 'resize-strategy'?

Resources