I am creating QLabel objects in my one class, and adding them to my QList<QLabel*> *objects. The QList is created in my main class with the command objects = new QList<QLabel*>(); and then sent to the class where the objects are created and added. This QList is also then sent to my movement class.
In my movement class I have a timer that detects if the QList is empty and if it is not, I run through all of the QLabel objects in the QList, and under some circumstances I move the QLabel object.
This is where my problem comes in. The code compiles perfectly and I have used debug and gone through the code, the move commands are executed perfectly and if i use qDebud() to display the x and y coordinate of the QLabel it returns the correct values however the movement is not updated on my display?
The QLabel gets deleted perfectly at the correct times and is removed from the screen, but the movements is not shown ?
Is there anyone with some insights into why this will be happening, and how to fix it?
The code moves widgets and debug output shows position changed but in
fact some widgets are still there at previous position. Why?
There is a possibility of some widget position updates being delayed. Try using this call:
QWidget::updateGeometry()
for(auto* pLabel : listOfLabels)
{
// and other actions suitable
// pLabel->move(newPoint(x, y));
pLabel->updateGeometry();
}
Related
I have a Qt application with objects derived from QGraphicsObjcet that need to be movable in a scene. I know that I can use the flags for movement to achieve this.
myObject->setFlag(QGraphicsItem::ItemIsMovable);
myObject->setFlag(QGraphicsItem::ItemIsSelectable);
myObject->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
but I am having an issue with the objects popping out of position when i use it. The only time when the objects move into an incorrect position is when an object I've moved is deleted and removed from the scene, the next time I try to move another object in the scene, its position relative to mouse Cursor is distorted until I release it and press it again. I realise that my problem could be occuring somewhere completely elsewhere in my code but from my own debugging I would at least want to try and implement the move functionality myself to solve this issue.
So my question is: How can you implement movable objects (derived from QGraphicsObject) that act as if the flags above are active?
I've been trying to use mouseMoveEvent but can't figure out how I get the objects to move with the cursor. Maybe I should look into DragMoveEvent instead? If possible, I would however really appreciate to see what the code for mouseMoveEvent below would look:
void myObject::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// How do I get myObject to follow
// the event pos in the scene from here?
QGraphicsObject::mouseMoveEvent(event);
update();
}
I think something like this should do the trick (not tested):
void myObject::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// Set the item position as the mouse position.
this->setPos(event->scenePos());
// If your object (this) has no parent, then setPos() place it using scene coordinates, which is what you need here.
QGraphicsObject::mouseMoveEvent(event);
update();
}
With the code above, your object is going to follow the mouse untill the end of the world, so you probably want to combine it with a start/stop flag.
And if your item has a parent, you are probably going to need to translate the coordinates.
I have a application in Qt, and a MainWindow. Now, I also added a helping QDialog which can be hooked up. This QDialog does not influence the programmflow, it just displays information.
But, it always starts on top of the MainWindow :/
SO I would like to start it on the side of the main window, so that it does not hinder the view to the main window?? How?
In my opinion , You should try this,
Use the overload of the QWidget::setParent() function to change the ownership of a QDialog widget, using set as NULL(but It will not share the parent's taskbar entry).
QDialog::show() returns control to the caller immediately, So it will not interfere in mainwindow flow.
Let's say, your application is in the full screen mode. Where then the QDialog should appear? It will be shown on the top and you won't be satisfied again.
If it doesn't influence the flow of the app then you are using it to communicate some sort of message. Can you use different ways? For instance, QStatusBar?
If not, why not to split the mainWindow with QSplitter or similar classes and provide an area where you can post all the info messages?
It sounds you want modaless dialog. In main window, use a slot to create the dialog.
void MainWindow::show_dialog()
{
if ( pDialog== NULL )
pDialog= new XYZ_Dialog(this);
QPoint p = pos();
QSize s = frameSize();
pDialog->setGeometry(p.x()+s.width(), p.y(), s.width()*1/2, s.height());
pDialog->show();
}
What I try to say is if the position of the new dialog bothers you, you set the position and size of it, before showing it.
Going up the learning curve and everything has been making sense so far except for this one:
I have a main window from where I call one or more dialog like this:
d->setWindowFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint);
d->setGeometry(etc...
d->show();
The dialogs are not bound to the main window, and they are actually set to be displayed right beside the main window looking like an extension.
To close the dialogs I use a mouse 'enterEvent' on the mainwindow to send a close signal to the dialog(s) which will use hide().
void MainWidget::enterEvent(QEvent *event)
{
emit signal_related_close();
}
This works but randomly this causes a very annoying issue. When the signal is sent to close the dialogs, the main window would loose focus and go in the background (behind whatever application that is on the screen). Note that it does not minimize but only goes in the background and like I said it is random (about one out of 3 times I do it). I can't seem to get a pattern.
I initially thought the signal was messed up and instead used a dialog::leaveEvent() but that didn't help. I also tried using dialog::mouseMoveEvent and using that to hide the dialog but that would still randomly loose focus on the application.
The only method that doesn't loose focus is using a push button on each dialog that will initiate the same hide commands but that's not great for my UI. So it would seem that using the mouse enterEvent/leaveEvent,mouseMoveEvent will cause that random issue.
Anyone experienced this issue before? Any idea what could be wrong? Thx.
I can't explain why but this problem occurred when using QEvent or any mouse related event together with recursive children widgets. For example take this code in the parent widget constructor:
ChildWidget c1 = new ChildWidget (this);
ChildWidget c2 = new ChildWidget (c1);
Childwidget c3 = new ChildWidget (c2);
Using QEvent in the parent widget will randomly make the window go to the background and loose focus.
Setting all the ChildWidget to the same parent stopped the problem.
I have 2 column. One of the columns is filled with lots of QWidgets.
When I drop a widget in a column I call this method:
void MainWindow::scrollToItem(Product_View *item) {
QPoint point = item->mapToParent(QPoint());
ui->scrollArea->ensureVisible(point.x(), point.y());
}
When I am at the bottom of the first column and I drag a widget in the next one. The scrollarea scrolls properly to the bottom so that I can see where I dropped it.
But when I drop the widget back in the first column, it scrolls but not entirely to the bottom. Its of about 150px (EDIT: 150px is not true. I only see about 5px of the Widget)
Can anybody help me?
EDIT:
maybe good to know my layout.
I have a mainwindow with a QScrollArea.
The scrollArea has a QWidget called scrollAreaWidgetContents and it has a QHBoxLayout.
The widget has 5 columns. And these have QVBoxLayout for my drag and drop widgets.
JEEZ ANOTHER EDIT:
I notice it only goes wrong with the last item.
I JUST KEEP ON EDITING
It is now clear to me that the scrollbar just isn't going all the way down.
QScrollBar *bar = ui->scrollArea->verticalScrollBar();
bar->setValue(bar->maximum());
This code also shows the same behaviour. What should I do with this thread? And should I create a new one?
The ensureVisible function only takes a point, so using it will only guarantee that one corner of your widget is visible (the top left, I believe?). Try using ensureWidgetVisible instead - this should make sure the entire widget makes it on-screen.
Hope that helps!
Although this is an older post I encountered the same problem and it gave me a lot of trouble finding a solution.
My problem:
Had to add a new line to a widget and then make sure the scroll bar scrolls down to it in order for people to view it. OP describes the issue well in his answer.
The things I tried are:
1. (Best way) To call processEvents() on the app object. I tried it after I saw this post and ratzian's answer.
2. Implement your custom ScrollArea,that extends QScrollArea and override the resize handler to be able to call ensureWidgetVisible on the added widget. Of course it somehow needs to know about that widget object.
3. Add a QTimer and start the timer upon adding a new widget. The method that the timer calls will need to call ensureWidgetVisible() on the new widget object and afterwards stop the timer.
I am aware that 3 is a bit hacky since it doesnt know when the resize event took place and so the timer will need to be set to a suboptimal value. (e.g resize is called in 33 ms and you set timer to 500 ms, you get the idea).
I hope this manages to help people who struggle with the same problem.
I found my problem. Not the solution.
If I drag the widget back to the first column, my code calls ensureWidgetVisible.
After that, my scrollArea resizes because of the new item. So thats why my widget isn't entirely visible.
I'm overloading the paint() function in QAbstractItemDelegate (my own Item delegate class).
When dragging, it paints the contents of the entire cell, which I don't want. I'm assuming that the paint() function is called with something specific while dragging, but I don't seem to find it.
The closest I've been able to find is a QState variable in the owning view class (access function QTableView::state() is protected.) By creating a function on my QTableView-derived class called 'isDragging()' which calls that function and returns whether dragging or no, I can determine within my delegate class whether I'm dragging or not, and can modify the paint() function.
This almost works.
The problem is that it shows the modified paint image in the original cell, which I don't want - I want to leave the image in the original cell untouched.
Have to scour the examples, I guess, and see if there's something that does this...
I have crawled through the Qt source and I can see where it sets the drag pixmap by calling the QItemDelegate::paint() function, but the only thing it changes is it forces QStyle::State_Selected in the item option style. That's not enough, since the item is selected, already.
Any way to know how to draw a cell's contents explicitly when dragging?
Ok, the ultimate answer on this was to, yes, set the flag on 'startDrag', but rather than leaving it around and unsetting it on mouse release button event, simply call the base method and then unset.
The reason is that the image for the cursor is only requested (and painted) once - not continuously during the drag, as I had first thought. Leaving the flag set meant the cursor image would get drawn at inappropriate times.
So, the implementation looks like:
MyClass::dragStart(Qt::DropActions supportedActions)
{
__dragStart = true;
TableView::dragStart(supportedActions);
// request for drag cursor image happens here
__dragStart = false;
}
Why don't you do that yourself? Set a flag when dragging starts and remember the active ModelIndex, do some special painting when the flag is set, and clear the flag when dragging is finished. You can do this by overriding QAbstractItemView::startDrag.