QGraphicsItem selection - qt

Does a simple method exist to select part of a QGraphicsItem (like for a selection, with a dashed border for example), despite its position in the QGraphicsScene
I've found QGraphicsItem::ItemIsSelectable but it doesn't help me much.
Thx

You can't select a part of QGraphicsItem. You can select whole item. Usualy it will draw a dashed rectangle around itself when selected.
You can select item by:
QGraphicsItem::setSelected
or
QGraphicsScene::setSelectionArea

Do you want to select it when you're clicking on it? If yes, you can override the mousePressEvent(QGraphicsSceneMouseEvent event) listener for this item, and use setSelected(). In Java (sorry about it), it would be something like:
#Override
public void mousePressEvent (QGraphicsSceneMouseEvent event) {
if (event.button() == Qt.MouseButton.LeftButton) {
this.setSelected(true);
}
}
If you want to select it with a left button of course. :)

You can call QGraphicsScene::setSelectionArea(QPainter path, QTransform), and later retrieve the area by calling selectionArea. However if you want to retrieve the items currently under selection, you will get only whole QGraphicsItems.

Here is an example of how to use ItemIsSelectable:
QGraphicsRectItem* item = new QGraphicsRectItem(rect);
item->setFlag(QGraphicsItem::ItemIsSelectable);
graphicsScene->addItem(item);
You can then connect the selectionChanged signal to a slot:
connect(graphicsScene, &QGraphicsScene::selectionChanged, this, &MyWidget::itemClicked);
Note that selectionChanged is triggered on double click only, not on a single click.

Related

How to catch QComboBox popup close event

A am using QComboBox derived class to show my items. My combo box is read only. But how can I catch the event when popup view of combo box closes?.For example, when user clicks a mouse button somewhere out of my combo box?
Thank you very much in advance.
What for do you want this event? If the QComboBox closes without selection nothing changed. The signals given will only be activated when a selection has been made.
If you insist on reading a "close-event", you could subclass focusOutEvent(QFocusEvent*) or use an event handler for the focus out event and emit a custom signal. Eventually you want to have a boolean flag set on hadEditFocus() before, so you can see if the dropdown would be opened.
Edit:
Eventually it would be easier to subclass and reimplement showPopup() and hidePopup() as:
void MyClass::showPopup()
{
QComboBox::showPopup();
emit signalPopupShown();
}
void MyClass::hidePopup()
{
QComboBox::hidePopup();
emit signalPopupHidden();
}
but I am not sure if hidePopup() gets called on focus-loose.

Qt, how to make Tooltip visible without hovering over the control?

I want tooltips to be visible by default when the container widget gets focus/visible.
I want tooltip to appear without being mouse hover on the respective control.
You need to subclass the widget and override handler(s) for event(s) which should produce tooltip display. In the handler, create a QHelpEvent of type QEvent::ToolTip and enqueue it at the event loop. Finally call the parent's original handler, to let it do what was originally intended.
So specifically for getting focus on button, it would be
class MyButton : public QPushButton {
virtual void focusInEvent(QFocusEvent *) {
if(evt->gotFocus()) {
QPoint pos(0,0);
QHelpEvent* help = new QHelpEvent(
QEvent::ToolTip,pos,this->mapToGlobal(pos));
QCoreApplication::postEvent(this,help);
}
QPushButton::focusInEvent(evt);
}
}
For visibility you would override
void QWidget::showEvent(QShowEvent * event);
and do similar code. You need to adjust relative pos to your taste, because originally tooltip dependens on mouse position which you don't have here. Also keep very tight control over making your widgets focused and/or visible. By default, something gets focus all the time, so you will get tooltips all over the place.

trigger mouseMoveEvent of several QGraphicsItem at the same time

When I select several QGraphicsItem (with Ctrl key) I can move them together, but the mouseMoveEvent is triggered only for the item that actually receives the event. Is there a way to make every selected items receive the event ? I can't find it in Qt's doc.
Could I group selected items together and handle it within QGraphicsView's mouseMoveEvent ?
Thanks a lot for any help :)
No there is no default way to do what you want as far as I know. Something you could do is the following:
Subclass QGraphicsScene and implement the mouseMoveEvent
In the mouse move event check if there is an item at the event position using the itemAt function
If there is an item and it is selected (isSelected), get all selected items of the scene.
For all selected items call the same function you would call.
Sample code follows:
void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
QPointF mousePosition = mouseEvent->scenePos();
QGraphicsItem* pItem = itemAt(mousePosition.x(), mousePosition.y());
if (pItem == NULL)
{
QGraphicsScene::mouseMoveEvent(mouseEvent);
return;
}
if (pItem->isSelected() == false)
{
QGraphicsScene::mouseMoveEvent(mouseEvent);
return;
}
// Get all selected items
QList<QGraphicsItem *> items = selectedItems();
for (unsinged i=0; i<items.count(); i++)
// Do what you want to do when a mouse move over a selected item.
items[i]->doSomething();
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
I'm reading between the lines of your question a little, but it sounds like you might be better served by implementing QGraphicsItem::itemChange on your QGraphicsItem class(es). This will get called whenever the position changes--whether by mouse, keyboard, programmatic, etc. You can even cancel the change if you want to.
http://doc.qt.io/qt-5/qgraphicsitem.html#itemChange

How to get event of clicking out of a QGraphicsItem, being notified of focusOut

i have a class implemented from QGraphicsItem, called Node.
i have a rectangle shaped "Node" and i can do something when user clicked on it
i use mousePress and mouseRelease events.
but i want to be notified when user clicked "out of" the rectangle shape.
i tried to implement these functions:
Qt Code:
void Node::focusInEvent ( QFocusEvent * event){
cout<<"in"<<endl;
update();
QGraphicsItem::focusInEvent(event);
}
void Node::focusOutEvent ( QFocusEvent * event ){
cout<<"out"<<endl;
update();
QGraphicsItem::focusOutEvent(event);
}
void Node::hoverEnterEvent(QGraphicsSceneHoverEvent *event){
cout<<"out"<<endl;
}
these do not reacts if i click in or out of rectangle.
should i set a logic on my own for example getting the mouse position and control if it is out of rectangle?
or is there a built in method?
or how can a "Node" object know if other Node object is clicked?
also i wonder, googled but could not found that when does focusinevent and focusoutevent triggered? I guess focusOutEvent must work when i had clicked in the item, then out of the item, am i wrong?
thanks for idea.
You need to do the following when you construct your nodes:
setFlag( QGraphicsItem::ItemIsFocusable );
setAcceptHoverEvents( true );
The first line makes your item actually capable of receiving focus, and the latter makes it so your item is notified of mouse events.
Have you called setFlags method of your graphics item with QGraphicsItem::ItemIsSelectable or QGraphicsItem::ItemIsMovable ?
According to QT doc.
By default, no flags are enabled.

On Qt widgets like DoubleSpinBox or ComboBox, how do i have custom right click menu

I have a few combo-boxes and double spin boxes on my Qt Dialog. Now I need a "ResetToDefault" item on a menu that comes up when you right click on the widget (spin box or combo box).
How do i get it. Is there some way I can have a custom menu that comes up on right click or Is there a way i can add items to the menu that comes on right click.
First, for Qt4, the simplest way is to create an action to reset the data, and add it the the widget using the addAction method (or use the designer). Then, set the contextMenuPolicy attribute to Qt::ActionsContextMenu. The context menu will appear and the action will be triggered.
Code example:
QAction *reset_act = new QAction("Reset to default");
mywidget->addAction(reset_act);
mywidget->setContextMenuPolicy(Qt::ActionsContextMenu);
// here connect the 'triggered' signal to some slot
For Qt3, you might have to intercept the context menu event, and thus inherit the QSpinBox and others. Or maybe you can intercept the context menu event from the main window, detect if it occurred above the widget supposed to have a context menu (using the QWidget::childAt method) and show it there. But you'll have to test.
For Qt4, you can do this for an editable QComboBox by using your own QLineEdit. Create a derived QLineEdit class which implements the contextMenuEvent
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
MyLineEdit(QWidget* parent = 0) : QLineEdit(parent){}
void contextMenuEvent(QContextMenuEvent *event)
{
QPointer<QMenu> menu = createStandardContextMenu();
//add your actions here
menu->exec(event->globalPos());
delete menu;
}
};
Then, use the setLineEdit function of QComboBox to set the line edit
MyLineEdit* edit = new MyLineEdit();
comboBox->setLineEdit(edit);
The combo box will now use your line edit class. The createStandardContextMenu function creates the normal context menu and you can add any new actions to it that you like in the contextMenuEvent handler before it is shown.
If the QComboBox is not editable then it doesn't have a default context menu so using the Qt::ActionsContextMenu method is much simpler.
QAbstractSpinBox also has a setLineEdit function so you can use a similar technique. Although, for some reason the setLineEdit function is protected on QAbstractSpinBox but public on QLineEdit.

Resources