Understanding QGraphicsProxyWidget::focusInEvent() in Qt Widgets


  • focusInEvent()
    This function is inherited from QGraphicsItem and overridden in QGraphicsProxyWidget. It's called whenever the embedded widget receives keyboard focus.
  • QGraphicsProxyWidget
    This class acts as an adapter, allowing you to embed a regular QWidget (like a button or text box) into a graphics scene.
  • You can potentially re-implement focusInEvent() in your custom QGraphicsProxyWidget subclass to perform actions when the embedded widget gains focus, such as highlighting the proxy or performing custom logic.
  • By default, QGraphicsProxyWidget itself doesn't handle focus events. This function is for handling focus events specifically for the embedded widget.
  • For focusInEvent() to be triggered, you need to set the focus policy of the embedded widget using setFocusPolicy(). This allows the widget to receive keyboard events.


#include <QtWidgets>
#include <QGraphicsScene>
#include <QGraphicsProxyWidget>

class HighlightingProxy : public QGraphicsProxyWidget {
  Q_OBJECT

public:
  HighlightingProxy(QWidget* widget, QGraphicsItem* parent = nullptr)
      : QGraphicsProxyWidget(widget, parent) {}

protected:
  void focusInEvent(QFocusEvent* event) override {
    // Call the base class implementation first
    QGraphicsProxyWidget::focusInEvent(event);

    // Highlight the proxy with a thicker pen when it gains focus
    setPen(QPen(Qt::red, 3));
  }

  void focusOutEvent(QFocusEvent* event) override {
    // Call the base class implementation first
    QGraphicsProxyWidget::focusOutEvent(event);

    // Reset the pen to default when it loses focus
    setPen(QPen(Qt::black, 1));
  }
};

int main(int argc, char* argv[]) {
  QApplication app(argc, argv);

  // Create a simple button widget
  QPushButton* button = new QPushButton("Click Me");
  button->setFocusPolicy(Qt::ClickFocus);  // Allow button to receive focus

  // Create a highlighting proxy for the button
  HighlightingProxy* proxy = new HighlightingProxy(button);

  // Add the proxy to a graphics scene
  QGraphicsScene scene;
  scene.addItem(proxy);

  // Show the scene in a window
  QGraphicsView view(&scene);
  view.show();

  return app.exec();
}
  1. We define a new class HighlightingProxy that inherits from QGraphicsProxyWidget.
  2. In the constructor, we store the embedded widget.
  3. We override the focusInEvent() and focusOutEvent() functions.
  4. In focusInEvent(), we call the base class implementation first (important!) and then change the pen of the proxy to a thicker red pen to visually indicate focus.
  5. In focusOutEvent(), we call the base class implementation and reset the pen to default.
  6. The main function creates a button widget, sets its focus policy, and creates a HighlightingProxy for it.
  7. It then adds the proxy to a scene and displays the scene in a window.


Signals and Slots

  • Connect these signals from the embedded widget within your QGraphicsProxyWidget to custom slots that perform the desired actions when focus changes.
  • You can leverage the existing signals provided by QWidget for focus events. These include:
    • focusObjectChanged(): Emitted whenever the widget receives or loses focus.
    • focusInEvent(): Emitted when the widget gains focus.
    • focusOutEvent(): Emitted when the widget loses focus.

QObject::installEventFilter()

  • You can override the eventFilter(QObject* obj, QEvent* event) function in your QGraphicsProxyWidget to specifically handle focus events (QFocusEvent) for the embedded widget.
  • This method allows you to install an event filter on the embedded widget. The event filter is a QObject that receives all events destined for the widget and can decide whether to handle them or pass them on.

Custom Event Handling

  • In your QGraphicsProxyWidget, connect to the custom signal and handle the event in a custom slot.
  • If you need more granular control, you can define your own custom event type and emit it from the embedded widget using QEvent::createVariety().

Choosing the Right Alternative

  • For more complex scenarios or if you need to intercept other events besides focus, consider using an event filter or custom events.
  • If you only need basic functionality like highlighting on focus change, overriding focusInEvent() or using focusObjectChanged() might be sufficient.
  • Custom events provide the most control but require more code.
  • Event filters offer more flexibility but can be less intuitive for beginners.
  • Using signals and slots is generally the most Qt-friendly approach.